﻿#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
租赁合同管理系统 - 主程序

这是系统的主入口文件,负责初始化应用程序、创建主窗口和管理核心功能。
"""

# 标准库导入
import sys
import os
import re
import warnings
import sqlite3
import json
import time
import traceback
from datetime import datetime, date, timedelta

# 忽略sipPyTypeDict()被弃用的警告
warnings.filterwarnings("ignore", category=DeprecationWarning, message=r"sipPyTypeDict\(\) is deprecated")

# 系统模块导入
from logging_integration import log_info, log_error, log_debug, log_warning, log_performance
from modern_theme import get_global_stylesheet, apply_global_theme, ModernTheme
from db_utils import DatabaseUtils
from logging_integration import record_operation, operation_logger
from user_auth import auth_manager
from notepad_tab import NotepadTab
from database_creator import DatabaseCreator
# PyQt导入
from PyQt5.QtCore import Qt, QTimer
from config_utils import config_manager
from auto_backup import AutoBackupManager, BackupSettings

# 第三方库导入
import pandas as pd
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font, PatternFill, Alignment

# 设置matplotlib中文显示
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
# 使用Windows系统常见的中文字体
plt.rcParams["font.family"] = ["Microsoft YaHei", "SimSun", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# PyQt5组件导入
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QTabWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QTableWidget, QTableWidgetItem, QHeaderView,
    QMessageBox, QDialog, QLineEdit, QDateEdit, QComboBox, QTextEdit,
    QFileDialog, QSplitter, QGroupBox, QFormLayout, QTreeWidget, QTreeWidgetItem,
    QMenu, QAction, QInputDialog, QDoubleSpinBox, QSpinBox, QScrollArea, QCheckBox,
    QProgressDialog, QFrame, QButtonGroup, QRadioButton, QAbstractItemView,
    QSizePolicy, QGridLayout, QListWidget, QListWidgetItem
)
from PyQt5.QtCore import QProcess
from PyQt5.QtCore import Qt, QDate, pyqtSignal, QTimer, QThread, QEvent, QRunnable, QThreadPool, pyqtSlot, QObject
from PyQt5.QtGui import QIcon, QFont, QColor, QBrush




from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.dates as mdates
import io
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors

# 中文字体设置已在前面完成

# 定义Worker类用于异步任务处理
class WorkerSignals(QObject):
    """信号类，用于Worker线程与主线程通信"""
    result = pyqtSignal(object)
    list_result = pyqtSignal(list, object)  # 支持列表和对象的信号
    error = pyqtSignal(tuple)
    finished = pyqtSignal()

class DataLoaderWorker(QRunnable):
    """后台数据加载Worker类"""
    def __init__(self, func=None, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()
    
    @pyqtSlot()
    def run(self):
        """在后台线程中执行任务"""
        try:
            if self.func:
                # 执行传入的函数
                result = self.func(*self.args, **self.kwargs)
                self.signals.result.emit(result)
            else:
                # 支持直接在Worker中执行数据库查询
                db_path = self.kwargs.get('db_path')
                query_type = self.kwargs.get('query_type')
                search_text = self.kwargs.get('search_text')
                
                if db_path and query_type:
                    import sqlite3
                    conn = sqlite3.connect(db_path)
                    cursor = conn.cursor()
                    
                    # 根据查询类型执行不同的查询
                    if query_type == 'load_contracts':
                        cursor.execute("""SELECT c.contract_no, c.sign_date, c.house_no, h.house_type, c.house_location, c.lessee, c.tenant, 
                                          c.start_date, c.end_date, c.status, c.payment_method, c.monthly_rent, c.quarterly_rent, c.total_rent, c.annual_rent, c.deposit,
                                          (SELECT COALESCE(SUM(amount), 0) FROM rent_records WHERE contract_no = c.contract_no) as received_rent
                                          FROM contracts c 
                                          LEFT JOIN houses h ON c.house_no = h.house_no""")
                    elif query_type == 'search_contracts':
                        if search_text:
                            search_param = f"%{search_text}%"
                            # 构建包含所有非数字列的搜索条件
                            search_query = """
                            SELECT c.contract_no, c.sign_date, c.house_no, h.house_type, c.house_location, c.lessee, c.tenant, 
                                   c.start_date, c.end_date, c.status, c.payment_method, c.monthly_rent, c.quarterly_rent, 
                                   c.total_rent, c.annual_rent, c.deposit,
                                   (SELECT COALESCE(SUM(amount), 0) FROM rent_records WHERE contract_no = c.contract_no) as received_rent
                            FROM contracts c 
                            LEFT JOIN houses h ON c.house_no = h.house_no
                            WHERE c.contract_no LIKE ? OR 
                                  c.sign_date LIKE ? OR 
                                  c.sign_year_month LIKE ? OR 
                                  c.house_location LIKE ? OR 
                                  h.house_type LIKE ? OR 
                                  c.lessor LIKE ? OR 
                                  c.legal_representative LIKE ? OR 
                                  c.person_in_charge LIKE ? OR 
                                  c.contact_phone LIKE ? OR 
                                  c.lessee LIKE ? OR 
                                  c.tenant LIKE ? OR 
                                  c.tenant_id LIKE ? OR 
                                  c.tenant_phone LIKE ? OR 
                                  c.start_date LIKE ? OR 
                                  c.end_date LIKE ? OR 
                                  c.status LIKE ? OR 
                                  c.payment_method LIKE ? OR 
                                  c.usage LIKE ? OR 
                                  c.utility_method LIKE ? OR 
                                  c.remarks LIKE ? OR
                                  c.payment_status LIKE ?
                            """
                            # 构建参数列表，每个字段对应一个搜索参数
                            params = [search_param] * 21
                            cursor.execute(search_query, params)
                        else:
                            # 搜索文本为空时，查询所有合同
                            cursor.execute("""SELECT c.contract_no, c.sign_date, c.house_no, h.house_type, c.house_location, c.lessee, c.tenant, 
                                              c.start_date, c.end_date, c.status, c.payment_method, c.monthly_rent, c.quarterly_rent, c.total_rent, c.annual_rent, c.deposit,
                                              (SELECT COALESCE(SUM(amount), 0) FROM rent_records WHERE contract_no = c.contract_no) as received_rent
                                              FROM contracts c 
                                              LEFT JOIN houses h ON c.house_no = h.house_no""")
                    
                    # 获取查询结果
                    result = cursor.fetchall()
                    conn.close()
                    
                    # 发送结果信号，包含结果和数据库路径
                    self.signals.list_result.emit(result, db_path)
        except Exception as e:
            traceback_info = traceback.format_exc()
            self.signals.error.emit((e, traceback_info))
        finally:
            self.signals.finished.emit()

"""
租赁合同管理系统主窗口类
"""
class MainWindow(QMainWindow):
    """
    系统主窗口类,负责管理整个应用程序的界面和功能
    """
    def __init__(self):
        """
        初始化主窗口
        """
        super().__init__()
        # 初始化变量
        self.last_tab_index = 0  # 记录上一个标签页索引,默认为仪表盘
        self.is_locked = False  # 初始化锁定状态,默认未锁定
        
        # 导入操作日志记录函数并设置为实例属性
        from operation_logger import record_operation
        self.record_operation = record_operation
        
        # 初始化配置管理
        self.init_configuration()
        
        log_info("启动租赁合同管理系统")
        self.initUI()
        self.initDatabase()
        self.initReminder()
        self.loadAllData()
        
        # 连接窗口显示事件,用于初始化窗口大小限制
        # 注意:这里不直接替换showEvent方法,而是通过事件过滤器实现
        self._shown_once = False
        
        # 获取应用实例并连接主屏幕变化信号
        app = QApplication.instance()
        if app and hasattr(app, 'primaryScreenChanged'):
            app.primaryScreenChanged.connect(self.on_primary_screen_changed)
        
        # 安装事件过滤器以捕获窗口变化事件和用户活动
        self.installEventFilter(self)
        
        # 初始化屏幕超时自动锁屏功能
        self.initScreenTimeoutLock()
    
    def init_configuration(self):
        """
        初始化配置管理
        
        加载系统配置，并可根据需要动态调整配置文件路径
        """
        # 记录当前使用的配置文件路径
        config_path = config_manager.get_config_path()
        log_info(f"当前使用的配置文件路径: {config_path}")
        
        # 加载配置
        self.config = config_manager.load_config()
        log_info("系统配置加载完成")
    
    def set_custom_config_path(self, config_path):
        """
        设置自定义配置文件路径
        
        Args:
            config_path (str): 自定义配置文件路径
            
        Returns:
            bool: 设置是否成功
        """
        # 设置新的配置文件路径
        success = config_manager.set_config_path(config_path)
        
        if success:
            # 重新加载配置
            self.config = config_manager.load_config()
            log_info(f"已切换到自定义配置文件: {config_path}")
            QMessageBox.information(self, "配置成功", 
                                   f"配置文件路径已更改为:\n{config_path}\n\n系统配置已重新加载。")
        else:
            log_error(f"设置自定义配置文件路径失败: {config_path}")
            QMessageBox.warning(self, "配置失败", 
                               f"无法设置配置文件路径:\n{config_path}\n\n请检查路径是否有效。")
            
        return success
        
    def applyModernTheme(self, theme_name=None):
        """应用现代UI主题
        
        Args:
            theme_name: 主题名称，可选值：'default', 'dark', 'blue', 'classic'
        """
        # 初始化主题
        if theme_name:
            self.theme = ModernTheme(theme_name)
            # 获取应用实例
            app = QApplication.instance()
            if app:
                self.theme.apply_theme(app)
                # 设置全局样式表
                app.setStyleSheet(get_global_stylesheet(theme_name))
        else:
            self.theme = ModernTheme()
            # 获取应用实例
            app = QApplication.instance()
            if app:
                self.theme.apply_theme(app)
                # 设置全局样式表
                app.setStyleSheet(get_global_stylesheet())
        
        # 更新仪表盘组件的主题样式
        try:
            # 检查是否有仪表盘标签页实例
            if hasattr(self, 'dashboard_tab') and self.dashboard_tab is not None:
                # 调用仪表盘的applyThemeStyle方法更新样式
                if hasattr(self.dashboard_tab, 'applyThemeStyle'):
                    self.dashboard_tab.applyThemeStyle()
        except Exception as e:
            # 出错时记录日志但不影响程序运行
            from logger_module import log_error
            log_error(f"更新仪表盘主题样式时出错: {str(e)}")
            
    def initScreenTimeoutLock(self):
        """
        初始化屏幕超时自动锁屏功能
        
        创建定时器、加载超时设置、初始化相关变量,并准备捕获用户活动事件
        """
        # 初始化变量
        from user_auth import auth_manager
        self.auth_manager = auth_manager
        self.is_locked = False
        self.timeout_seconds = 30 * 60  # 默认30分钟
        
        # 创建定时器
        self.idle_timer = QTimer(self)
        self.idle_timer.setSingleShot(True)
        self.idle_timer.timeout.connect(self.onScreenTimeout)
        
        # 加载屏幕超时设置
        self.loadScreenTimeoutSetting()
        
        # 开始计时
        self.resetIdleTimer()
        
        # 记录日志
        log_info(f"屏幕超时自动锁屏功能初始化完成,超时时间设置为{self.timeout_seconds // 60}分钟")
    
    def loadScreenTimeoutSetting(self):
        """
        从数据库加载屏幕超时设置
        """
        try:
            # 连接数据库
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                raise Exception("无法获取数据库连接")
            cursor = conn.cursor()
            
            # 查询屏幕超时设置
            cursor.execute("SELECT screen_timeout_minutes FROM reminder_settings LIMIT 1")
            result = cursor.fetchone()
            
            if result and result[0] is not None:
                self.timeout_seconds = int(result[0]) * 60  # 转换为秒
            else:
                self.timeout_seconds = 30 * 60  # 默认30分钟
            
            DatabaseUtils.close_connection(conn)
            log_debug(f"加载屏幕超时设置: {self.timeout_seconds // 60}分钟")
        except Exception as e:
            log_error(f"加载屏幕超时设置失败: {str(e)}")
            self.timeout_seconds = 30 * 60  # 默认30分钟
    
    def resetIdleTimer(self):
        """
        重置空闲时间定时器
        当检测到用户活动时调用此方法
        """
        if self.is_locked:
            return  # 已锁定状态不重置定时器
            
        # 检查idle_timer是否已经初始化
        if hasattr(self, 'idle_timer') and self.idle_timer:
            self.idle_timer.stop()
            self.idle_timer.start(self.timeout_seconds * 1000)  # 转换为毫秒
            log_debug("重置屏幕超时定时器")
    
    def updateScreenTimeout(self, minutes):
        """
        更新屏幕超时时间
        
        参数:
            minutes: 超时时间（分钟）
        """
        try:
            # 转换为秒
            self.timeout_seconds = int(minutes) * 60
            # 重置定时器
            self.resetIdleTimer()
            log_info(f"屏幕超时时间已更新为{minutes}分钟")
            return True
        except Exception as e:
            log_error(f"更新屏幕超时时间失败: {str(e)}")
            return False
    
    def onScreenTimeout(self):
        """
        当屏幕超时时触发锁屏
        """
        if not self.is_locked and self.auth_manager.is_authenticated:
            log_info("屏幕超时,触发自动锁屏")
            self.lockScreen()
    
    def showThemeSelection(self):
        """显示主题选择对话框"""
        # 定义可用的主题列表
        themes = [
            ('默认主题', 'default'),
            ('深色主题', 'dark'),
            ('蓝色主题', 'blue'),
            ('经典主题', 'classic')
        ]
        
        # 获取当前主题
        current_theme = self.theme.theme_name if hasattr(self, 'theme') else 'default'
        current_index = 0
        for i, (_, theme_name) in enumerate(themes):
            if theme_name == current_theme:
                current_index = i
                break
        
        # 创建主题选择对话框
        from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QComboBox, QPushButton, QFrame
        from PyQt5.QtCore import Qt
        
        dialog = QDialog(self)
        dialog.setWindowTitle('更换主题')
        dialog.setFixedSize(300, 180)
        dialog.setWindowModality(Qt.ApplicationModal)
        
        layout = QVBoxLayout(dialog)
        
        # 添加标题
        title_label = QLabel('请选择您喜欢的主题：')
        title_label.setStyleSheet('font-size: 14px; font-weight: bold; margin-bottom: 15px;')
        layout.addWidget(title_label)
        
        # 添加主题选择下拉框
        theme_combo = QComboBox()
        for display_name, _ in themes:
            theme_combo.addItem(display_name)
        theme_combo.setCurrentIndex(current_index)
        theme_combo.setStyleSheet('padding: 5px; margin-bottom: 20px;')
        layout.addWidget(theme_combo)
        
        # 添加分隔线
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        layout.addWidget(line)
        
        # 添加按钮布局
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        
        # 确定按钮
        ok_btn = QPushButton('确定')
        ok_btn.clicked.connect(lambda: self.onThemeSelected(theme_combo.currentIndex(), themes, dialog))
        btn_layout.addWidget(ok_btn)
        
        # 取消按钮
        cancel_btn = QPushButton('取消')
        cancel_btn.clicked.connect(dialog.close)
        btn_layout.addWidget(cancel_btn)
        
        layout.addLayout(btn_layout)
        
        # 显示对话框
        dialog.exec_()
    
    def onThemeSelected(self, index, themes, dialog):
        """处理主题选择"""
        theme_name = themes[index][1]
        
        # 应用新主题
        self.applyModernTheme(theme_name)
        
        # 更新配置文件
        config = config_manager.load_config()
        config['theme'] = theme_name
        config_manager.save_config(config)
        
        # 记录主题变更日志
        log_info(f"用户切换主题为: {themes[index][0]} ({theme_name})")
        
        # 关闭对话框
        dialog.close()
    
    def lockScreen(self):
        """
        锁定屏幕,显示锁屏对话框
        """
        from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox
        from PyQt5.QtCore import Qt
        
        class ScreenLockDialog(QDialog):
            def __init__(self, parent=None, auth_manager=None):
                super().__init__(parent)
                self.auth_manager = auth_manager
                self.setWindowTitle("屏幕锁定")
                self.setFixedSize(300, 200)
                self.setWindowModality(Qt.ApplicationModal)
                self.initUI()
            
            def initUI(self):
                layout = QVBoxLayout(self)
                layout.setAlignment(Qt.AlignCenter)
                
                # 标题
                title_label = QLabel("屏幕已锁定")
                title_label.setStyleSheet("font-size: 16px; font-weight: bold; margin-bottom: 20px;")
                title_label.setAlignment(Qt.AlignCenter)
                
                # 提示
                hint_label = QLabel("请输入当前用户密码解锁")
                hint_label.setAlignment(Qt.AlignCenter)
                hint_label.setStyleSheet("margin-bottom: 15px;")
                
                # 密码输入框
                self.password_input = QLineEdit()
                self.password_input.setEchoMode(QLineEdit.Password)
                self.password_input.setPlaceholderText("输入密码")
                self.password_input.setMinimumHeight(30)
                self.password_input.returnPressed.connect(self.unlock)
                
                # 按钮布局
                btn_layout = QHBoxLayout()
                unlock_btn = QPushButton("解锁")
                unlock_btn.setMinimumHeight(30)
                unlock_btn.clicked.connect(self.unlock)
                btn_layout.addWidget(unlock_btn)
                
                layout.addWidget(title_label)
                layout.addWidget(hint_label)
                layout.addWidget(self.password_input)
                layout.addLayout(btn_layout)
                
                # 自动聚焦到密码输入框
                self.password_input.setFocus()
            
            def unlock(self):
                password = self.password_input.text()
                if self.verify_password(password):
                    self.accept()
                else:
                    QMessageBox.warning(self, "验证失败", "密码错误,请重新输入")
                    self.password_input.clear()
                    self.password_input.setFocus()
            
            def verify_password(self, password):
                """
                验证用户密码
                
                参数:
                    password: 要验证的密码
                    
                返回:
                    bool: 密码是否正确
                """
                from db_utils import DatabaseUtils
                try:
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    cursor.execute("SELECT password FROM users WHERE username = ?", 
                                  (self.auth_manager.current_user,))
                    result = cursor.fetchone()
                    DatabaseUtils.close_connection(conn)
                    
                    return result and result[0] == password
                except Exception as e:
                    log_error(f"密码验证过程中发生错误: {str(e)}")
                    return False
        
        # 设置锁定状态
        self.is_locked = True
        
        # 保存当前窗口透明度
        self.original_window_opacity = self.windowOpacity()
        # 设置窗口半透明,使主界面内容模糊化
        self.setWindowOpacity(0.1)
        
        # 记录操作日志
        self.record_operation(
            user_id=self.auth_manager.current_user_id,
            username=self.auth_manager.current_user,
            operation_module="系统安全",
            operation_content="屏幕自动锁定",
            operation_result="成功",
            detail={"原因": "屏幕超时自动锁定"}
        )
        
        # 显示锁屏对话框
        lock_dialog = ScreenLockDialog(self, self.auth_manager)
        result = lock_dialog.exec_()
        
        # 无论对话框是接受还是拒绝,都恢复窗口透明度
        # 恢复窗口原始透明度
        self.setWindowOpacity(self.original_window_opacity)
        
        if result == QDialog.Accepted:
            # 解锁成功
            self.is_locked = False
            self.resetIdleTimer()
            
            # 记录解锁日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统安全",
                operation_content="屏幕解锁",
                operation_result="成功",
                detail={"验证结果": "密码验证通过,屏幕解锁"}
            )
        else:
            # 对话框被其他方式关闭（如点击关闭按钮或按ESC键）
            # 保持锁定状态,但重置定时器继续计时
            self.resetIdleTimer()
            log_info("锁屏对话框被关闭,保持锁定状态并重置计时器")
    
    def get_software_title(self):
        """获取软件品牌、名称和版本,用于窗口标题显示"""
        conn = None
        cursor = None
        try:
            from db_utils import DatabaseUtils
            
            # 使用DatabaseUtils获取最新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,获取软件标题失败")
                return '租赁合同管理系统'
                
            cursor = conn.cursor()
            
            # 检查system_params表是否存在
            cursor.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'")
            if cursor.fetchone()[0] == 0:
                # 表不存在,使用默认值
                return '租赁合同管理系统'
            
            # 查询软件信息
            params = {}
            for key in ['software_brand', 'software_name', 'software_version']:
                cursor.execute("SELECT value FROM system_params WHERE key=?", (key,))
                result = cursor.fetchone()
                params[key] = result[0] if result else ''
            
            # 格式化标题
            title_parts = []
            if params['software_brand']:
                title_parts.append(params['software_brand'])
            if params['software_name']:
                title_parts.append(params['software_name'])
            if params['software_version']:
                title_parts.append(f"{params['software_version']}")
            
            # 如果没有获取到任何信息,返回默认标题
            if not title_parts:
                return '租赁合同管理系统'
            
            return ''.join(title_parts)
        except Exception as e:
            log_error(f"获取软件标题失败: {str(e)}")
            # 发生任何错误时返回默认值
            return '租赁合同管理系统'
        finally:
            # 使用DatabaseUtils关闭连接
            if conn:
                DatabaseUtils.close_connection(conn)
                cursor = None
                conn = None
    
    def initUI(self):
        """
        初始化用户界面
        
        功能: 设置窗口标题、大小,应用现代主题,创建中央部件、主布局和各功能标签页,并连接相关信号和槽
        """
        # 导入用户认证模块
        from user_auth import auth_manager
        from operation_logger import record_operation
        
        # 设置窗口标题
        window_title = self.get_software_title()
        self.setWindowTitle(window_title)
        
        # 设置最小窗口大小
        self.setMinimumSize(1024, 768)
        
        # 初始化窗口状态变量
        self._shown_once = False
        self._shown_optimized = False
        
        # 安装事件过滤器
        self.installEventFilter(self)
        
        # 连接主屏幕变化信号
        QApplication.instance().primaryScreenChanged.connect(self.on_primary_screen_changed)
        
        # 不再设置固定的窗口大小,而是在窗口显示时最大化
        # 只保留最小尺寸限制,让窗口在显示时自动最大化
        log_info(f"初始化用户界面,设置最小窗口大小并准备最大化显示")
        
        log_info(f"初始化用户界面,设置窗口标题: {window_title}、初始大小和最小大小")
        
        # 禁用窗口右上角的关闭按钮,但保留最大化和最小化按钮
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)
        log_info("已禁用窗口右上角的关闭按钮,保留最大化和最小化功能")
        
        # 应用现代主题 - 从配置加载保存的主题设置
        theme_name = self.config.get('theme', 'default')
        self.applyModernTheme(theme_name)
        log_info(f"应用现代UI主题: {theme_name}")
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        log_debug("创建中央部件")
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        log_debug("创建主布局")
        
        # 创建用户信息和操作栏
        user_bar_layout = QHBoxLayout()
        user_bar_layout.setContentsMargins(10, 5, 10, 5)
        
        # 创建用户信息标签（将在状态栏中使用）
        self.user_info_label = QLabel(f'当前用户: {auth_manager.current_user} ({auth_manager.current_role})')
        self.user_info_label.setStyleSheet('font-size: 14px;')
        
        # 创建日期时间标签（将在状态栏中使用）
        self.datetime_label = QLabel()
        self.datetime_label.setStyleSheet('font-size: 14px;')
        
        # 创建出租方信息标签（将在状态栏中使用）
        self.landlord_label = QLabel()
        self.landlord_label.setStyleSheet('font-size: 14px;')
        
        # 创建数据库名称标签（将在状态栏中使用）
        self.db_name_label = QLabel()
        self.db_name_label.setStyleSheet('font-size: 14px;')
        
        # 设置定时器更新日期时间
        self.datetime_timer = QTimer(self)
        self.datetime_timer.timeout.connect(self.update_datetime_label)
        self.datetime_timer.start(1000)  # 每秒更新一次
        self.update_datetime_label()  # 立即更新一次
        
        # 初始化出租方信息和数据库名称
        self.update_db_name_label()
        
        # 创建状态栏并添加标签
        status_bar = self.statusBar()
        status_bar.addWidget(self.landlord_label)
        # 添加分隔符
        separator1 = QLabel(" | ")
        separator1.setStyleSheet('font-size: 14px;')
        status_bar.addWidget(separator1)
        # 添加用户信息标签到状态栏,放置在单位名称标签后方
        status_bar.addWidget(self.user_info_label)
        # 添加另一个分隔符
        separator2 = QLabel(" | ")
        separator2.setStyleSheet('font-size: 14px;')
        status_bar.addWidget(separator2)
        # 添加数据库名称标签到状态栏,放置在当前用户标签后方
        status_bar.addWidget(self.db_name_label)
        # 添加另一个分隔符
        separator3 = QLabel(" | ")
        separator3.setStyleSheet('font-size: 14px;')
        status_bar.addWidget(separator3)
        # 添加日期时间标签到状态栏,放置在数据库名称标签后方
        status_bar.addPermanentWidget(self.datetime_label)  # 使用addPermanentWidget实现水平靠右对齐
        self.update_landlord_label()
        
        user_bar_layout.addStretch()
        
        # 更换主题按钮
        change_theme_btn = QPushButton('更换主题')
        change_theme_btn.clicked.connect(self.showThemeSelection)
        user_bar_layout.addWidget(change_theme_btn)
        
        # 锁屏按钮
        lock_screen_btn = QPushButton('锁屏')
        lock_screen_btn.clicked.connect(self.lockScreen)
        user_bar_layout.addWidget(lock_screen_btn)
        
        # 切换用户按钮
        switch_user_btn = QPushButton('切换用户')
        switch_user_btn.clicked.connect(self.onSwitchUser)
        user_bar_layout.addWidget(switch_user_btn)
        
        # 修改密码按钮
        change_password_btn = QPushButton('修改密码')
        change_password_btn.clicked.connect(self.onChangePassword)
        user_bar_layout.addWidget(change_password_btn)
        
        # 退出登录按钮
        logout_btn = QPushButton('退出登录')
        logout_btn.clicked.connect(self.onLogout)
        user_bar_layout.addWidget(logout_btn)
        
        # 将用户操作栏添加到主布局
        main_layout.addLayout(user_bar_layout)
        
        # 创建标签页
        self.tabs = QTabWidget()
        self.dashboard_tab = DashboardTab()
        self.contract_tab = ContractTab(self)
        self.rent_tab = RentTab(self)

        self.report_tab = ReportTab()
        self.basic_data_tab = BasicDataTab()
        self.system_setting_tab = SystemSettingTab()
        self.notepad_tab = NotepadTab()  # 新增记事本标签
        self.basic_info_tab = BasicInfoTab()
        
        self.tabs.addTab(self.dashboard_tab, '仪表盘')
        self.tabs.addTab(self.contract_tab, '合同管理')
        self.tabs.addTab(self.rent_tab, '租金管理')
        self.tabs.addTab(self.report_tab, '报表统计')
        self.tabs.addTab(self.basic_data_tab, '基础资料')
        
        # 根据用户角色控制显示的标签页
        if auth_manager.has_permission('管理员'):
            self.tabs.addTab(self.system_setting_tab, '系统设置')
        
        self.tabs.addTab(self.notepad_tab, '笔记')  # 在关于页面前添加笔记标签
        self.tabs.addTab(self.basic_info_tab, '关于')
        log_info("创建并添加所有功能标签页")
        
        # 添加标签页到主布局
        main_layout.addWidget(self.tabs)
        log_debug("将标签页添加到主布局")
        
        # 连接信号和槽
        self.contract_tab.data_updated.connect(self.updateDashboard)
        self.rent_tab.data_updated.connect(self.updateDashboard)
        self.notepad_tab.data_updated.connect(self.updateDashboard)  # 连接记事本数据更新信号

        log_debug("连接数据更新信号和槽")
        
        # 连接标签页切换信号,实现合同管理页面切换时自动刷新数据
        self.tabs.currentChanged.connect(self.onTabChanged)
        log_debug("连接标签页切换信号和槽")
    
    def update_datetime_label(self):
        """更新日期时间标签的内容"""
        try:
            # 获取当前日期、时间和星期
            now = datetime.now()
            weekday_map = {0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六', 6: '周日'}
            weekday = weekday_map.get(now.weekday(), '')
            
            # 格式化显示
            datetime_str = now.strftime(f'%Y年%m月%d日 %H:%M:%S {weekday}')
            self.datetime_label.setText(datetime_str)
        except KeyboardInterrupt:
            # 捕获用户中断操作，确保程序不会崩溃
            log_debug("用户中断操作被捕获")
            # 继续执行，不做特殊处理，允许定时器继续运行
        except Exception as e:
            # 捕获其他可能的异常
            log_error(f"更新日期时间标签时出错: {str(e)}")
    
    def update_landlord_label(self):
        """更新出租方信息标签的内容"""
        conn = None
        try:
            conn = DatabaseUtils.get_connection()
            if conn:
                cursor = conn.cursor()
                # 查询默认出租方信息
                cursor.execute("SELECT landlord_name FROM landlords WHERE is_default = 1 LIMIT 1")
                result = cursor.fetchone()
                if result and result[0]:
                    # 如果有默认出租方
                    self.landlord_label.setText(f"单位名称: {result[0]}")
                else:
                    # 如果没有默认出租方,尝试查询第一个出租方
                    cursor.execute("SELECT landlord_name FROM landlords LIMIT 1")
                    result = cursor.fetchone()
                    if result and result[0]:
                        self.landlord_label.setText(f"单位名称: {result[0]}")
                    else:
                        self.landlord_label.setText("单位名称: 未设置")
        except Exception as e:
            log_error(f"获取默认出租方信息失败: {str(e)}")
            self.landlord_label.setText("单位名称: 获取失败")
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def update_db_name_label(self):
        """从配置管理中读取并更新状态栏显示的数据库名称标签"""
        try:
            from config_utils import ConfigManager
            # 从ConfigManager获取数据库路径
            db_path = ConfigManager.get_database_path()
            
            if db_path:
                # 提取数据库文件名
                db_name = os.path.basename(db_path)
                self.db_name_label.setText(f"当前数据库名称:{db_name}")
                log_info(f"状态栏数据库名称更新为: {db_name}")
            else:
                self.db_name_label.setText("当前数据库名称:未连接")
                log_info("数据库未连接,状态栏显示已更新")
        except Exception as e:
            log_error(f"更新数据库名称标签时出错: {str(e)}")
            self.db_name_label.setText("当前数据库名称:未知")
        
    def eventFilter(self, obj, event):
        """
        事件过滤器
        
        功能: 捕获窗口的各种事件,包括显示事件、变化事件和用户活动事件
        
        参数:
            obj: 事件对象
            event: 事件类型
            
        返回:
            bool: 是否继续传递事件
        """
        # 捕获用户活动事件,重置屏幕超时定时器
        activity_events = [
            QEvent.MouseMove,
            QEvent.MouseButtonPress,
            QEvent.MouseButtonRelease,
            QEvent.KeyPress,
            QEvent.KeyRelease,
            QEvent.Wheel,
            QEvent.WindowActivate
        ]
        
        if event.type() in activity_events and not self.is_locked:
            # 重置屏幕超时定时器
            self.resetIdleTimer()
        
        if obj == self:
            # 捕获显示事件
            if event.type() == QEvent.Show and not self._shown_once:
                self._shown_once = True
                # 设置窗口大小限制
                self._update_window_size_limits()
                # 确保窗口大小合适
                self._ensure_proper_window_size()
            # 捕获窗口变化事件,检测窗口是否移动到其他屏幕
            elif event.type() == QEvent.Move or event.type() == QEvent.WindowActivate:
                # 检查窗口是否移动到了新屏幕
                self._check_screen_change()
        return super(MainWindow, self).eventFilter(obj, event)
            
    def on_primary_screen_changed(self, screen):
        """
        主屏幕变化时的事件处理函数
        
        功能: 当系统主屏幕变化时,更新窗口大小限制
        
        参数:
            screen: 新的主屏幕对象
        """
        # 更新窗口大小限制
        self._update_window_size_limits()
        
        # 确保窗口大小合适
        self._ensure_proper_window_size()
        log_info("主屏幕发生变化,已更新窗口大小限制")
    
    def _check_screen_change(self):
        """
        检查窗口是否移动到了不同的屏幕
        
        功能: 比较当前屏幕与上次记录的屏幕,如果不同则更新窗口大小限制
        """
        # 获取当前屏幕
        current_screen = self.screen()
        
        # 检查是否需要初始化或屏幕已更改
        if not hasattr(self, '_last_screen') or self._last_screen != current_screen:
            # 更新上次屏幕引用
            self._last_screen = current_screen
            
            # 更新窗口大小限制
            self._update_window_size_limits()
            
            # 确保窗口大小合适
            self._ensure_proper_window_size()
            log_info("窗口移动到新屏幕,已更新窗口大小限制")
        
    def _update_window_size_limits(self):
        """
        更新窗口大小限制
        
        功能: 移除最大尺寸限制,允许窗口完全最大化
        """
        # 移除最大尺寸限制,允许窗口完全最大化
        self.setMaximumSize(16777215, 16777215)  # 使用Qt默认的最大整数
        log_debug(f"已移除窗口最大尺寸限制,允许窗口完全最大化")
    
    def _ensure_proper_window_size(self):
        """
        确保窗口大小合适
        
        功能: 根据当前屏幕尺寸,将窗口调整到合适大小或直接最大化显示
        """
        # 获取当前屏幕
        screen = self.screen()
        if not screen:
            log_warning("无法获取屏幕信息,跳过窗口大小调整")
            return
            
        # 直接最大化窗口
        self.showMaximized()
        log_info(f"窗口已最大化显示")
                
    def showEvent(self, event):
        """
        窗口显示事件处理函数
        
        功能: 确保窗口在显示时能够正确地适应屏幕尺寸
        
        参数:
            event: 显示事件对象
        """
        super(MainWindow, self).showEvent(event)
        # 窗口首次显示或被显示时,强制调整窗口大小
        if not hasattr(self, '_shown_optimized') or not self._shown_optimized:
            # 延迟一点时间确保窗口完全初始化
            QTimer.singleShot(100, self._force_optimize_window_size)
    
    def _force_optimize_window_size(self):
        """
        强制优化窗口大小
        
        功能: 忽略当前窗口大小,直接最大化显示窗口
        """
        # 直接最大化窗口
        self.showMaximized()
        self._shown_optimized = True
        log_info(f"强制最大化窗口显示")
    
    def initDatabase(self):
        """
        使用ConfigManager初始化数据库连接
        
        功能: 从配置管理读取数据库路径,建立与SQLite数据库的连接,并确保所有必要的数据库表存在
        
        异常:
            Exception: 数据库连接或操作出错时抛出
        """
        try:
            # 导入必要的模块
            from config_utils import ConfigManager
            from db_utils import DatabaseUtils
            
            # 从配置文件加载数据库路径,如果没有则使用默认路径
            log_info("开始初始化数据库路径...")
            saved_db_path = ConfigManager.get_database_path()
            log_info(f"从配置文件读取的数据库路径: {saved_db_path}")
            
            # 验证数据库路径和权限
            if (saved_db_path and os.path.exists(saved_db_path) 
                and os.access(saved_db_path, os.R_OK | os.W_OK)):
                self.db_path = saved_db_path
                log_info(f"✓ 使用配置文件中的数据库路径: {self.db_path}")
            else:
                # 使用默认路径
                self.db_path = os.path.abspath('rental_contract.db')
                log_info(f"✗ 配置文件路径不存在、无效或无读写权限,使用默认数据库路径: {self.db_path}")
                
                # 尝试创建默认数据库文件（如果不存在）
                try:
                    if not os.path.exists(self.db_path):
                        open(self.db_path, 'a').close()
                        log_info(f"✓ 默认数据库文件已创建: {self.db_path}")
                    
                    # 保存默认路径到配置文件
                    save_result = ConfigManager.set_database_path(self.db_path)
                    log_info(f"✓ 保存默认路径到配置文件: {'成功' if save_result else '失败'}")
                except Exception as file_error:
                    log_error(f"✗ 创建默认数据库文件或保存配置失败: {str(file_error)}")
            
            # 设置数据库路径
            log_info(f"当前数据库路径: {self.db_path}")
            
            # 初始化DatabaseUtils,确保使用最新的数据库连接
            log_info(f"设置DatabaseUtils数据库路径为: {self.db_path}")
            DatabaseUtils.set_db_path(self.db_path)
            
            # 验证设置是否成功
            current_db_path = DatabaseUtils.get_db_path()
            if current_db_path == self.db_path:
                log_info(f"✓ DatabaseUtils路径设置成功: {current_db_path}")
            else:
                log_error(f"✗ DatabaseUtils路径设置失败: 期望{self.db_path},实际{current_db_path}")
            
            # 获取连接以进行初始化操作
            conn = DatabaseUtils.get_connection()
            if conn:
                try:
                    # 确保操作日志表存在
                    DatabaseUtils.ensure_operation_logs_table_exists(conn)
                    log_info("确保operation_logs表存在")
                    
                    # 检查并更新现有的提醒设置表（如果需要）
                    self.checkAndUpdateReminderSettingsTable(conn)
                    
                    # 验证数据库连接
                    cursor = conn.cursor()
                    cursor.execute("SELECT 1")
                    log_info("✓ 数据库连接验证成功")
                except Exception as db_op_error:
                    log_error(f"✗ 数据库操作失败: {str(db_op_error)}")
                finally:
                    # 关闭临时连接
                    DatabaseUtils.close_connection(conn)
            
            # 更新状态栏显示的数据库名称
            self.update_db_name_label()
            
            log_info("数据库初始化完成")
        except Exception as e:
            log_error(f"数据库连接或初始化失败: {str(e)}")
            raise
    
    def closeEvent(self, event):
        """
        重写closeEvent方法,拦截所有关闭窗口的尝试
        
        参数:
            event: 关闭事件对象
        """
        # 忽略关闭事件,阻止窗口关闭
        event.ignore()
        
    def checkAndUpdateReminderSettingsTable(self, conn=None):
        """
        检查并更新reminder_settings表结构
        
        功能: 检查reminder_settings表中是否存在reminder_frequency列,如果不存在则添加该列并设置默认值
        
        参数:
            conn: 数据库连接对象,如果不提供则使用self.conn
            
        异常:
            Exception: 表结构检查或更新过程中出现任何异常时捕获并记录
        """
        # 获取连接
        if conn is None:
            conn = DatabaseUtils.get_connection()
            if not conn:
                log_error("无法获取数据库连接以检查reminder_settings表")
                return
                
        cursor = conn.cursor()
        # 检查reminder_frequency列是否存在
        try:
            cursor.execute("PRAGMA table_info(reminder_settings)")
            columns = [column[1] for column in cursor.fetchall()]
            
            # 如果reminder_frequency列不存在,添加它
            if 'reminder_frequency' not in columns:
                cursor.execute("ALTER TABLE reminder_settings ADD COLUMN reminder_frequency INTEGER DEFAULT 30")
                conn.commit()
                log_info("已添加reminder_frequency列到reminder_settings表")
            else:
                log_debug("reminder_settings表结构已包含reminder_frequency列,无需更新")
        except Exception as e:
            log_error(f"检查并更新reminder_settings表结构时出错: {str(e)}")
    
    def initReminder(self):
        """
        初始化提醒系统
        
        功能: 初始化提醒定时器,设置提醒检查频率,并立即执行一次提醒检查
        
        异常:
            任何提醒系统初始化过程中的异常将被全局日志记录器捕获
        """
        try:
            log_info("初始化提醒系统")
            
            # 初始化提醒定时器
            self.reminder_timer = QTimer(self)
            self.reminder_timer.timeout.connect(self.checkReminders)
            log_debug("初始化提醒定时器")
            
            # 获取默认提醒频率
            default_frequency = 60  # 默认60分钟
            try:
                # 使用DatabaseUtils获取数据库连接和cursor
                conn = DatabaseUtils.get_connection()
                if conn:
                    cursor = conn.cursor()
                    # 从数据库获取提醒频率设置
                    cursor.execute("SELECT reminder_frequency FROM reminder_settings LIMIT 1")
                    result = cursor.fetchone()
                    if result:
                        default_frequency = result[0]
                    log_debug(f"获取提醒频率设置: {default_frequency}分钟")
                    DatabaseUtils.close_connection(conn)
                else:
                    log_warning("无法获取数据库连接,使用默认提醒频率")
            except Exception as e:
                log_warning(f"获取提醒频率设置失败,使用默认值: {str(e)}")
            
            # 启动定时器,根据设置的频率检查提醒
            self.reminder_timer.start(default_frequency * 60 * 1000)
            log_info(f"启动提醒定时器,频率: {default_frequency}分钟")
            
            # 立即检查一次提醒
            self.checkReminders()
            log_debug("立即执行一次提醒检查")
        except Exception as e:
            log_error(f"初始化提醒系统时出错: {str(e)}")
        
    def on_new_reminders_available(self, reminders):
        """
        当有新提醒可用时调用的槽函数
        
        参数:
            reminders (list): 包含新提醒信息的列表
        
        功能: 当收到新提醒时,创建临时QTreeWidget显示提醒内容,并更新提醒标签页
        
        异常:
            Exception: 显示提醒过程中出现任何异常时捕获并记录
        """
        try:
            # 显示提醒对话框
            if reminders:
                log_info(f"收到新提醒,数量: {len(reminders)}")
                # 创建一个临时的QTreeWidget来显示提醒
                temp_tree = QTreeWidget()
                temp_tree.setHeaderLabels(['状态', '提醒类型', '提醒内容', '日期', '详情'])
                
                # 使用show_combined_reminders函数来显示提醒
                show_combined_reminders(self.enhanced_reminder, temp_tree, '全部提醒')
                log_debug("已显示新提醒对话框")
        except Exception as e:
            log_error(f"显示提醒时出错:{str(e)}")
        
    def updateReminderFrequency(self, minutes):
        """
        更新提醒检查频率
        
        参数:
            minutes (int): 新的提醒检查频率（分钟）
        
        功能: 停止当前的提醒定时器,并使用新的频率重新启动定时器
        
        异常:
            Exception: 更新提醒频率过程中出现任何异常时捕获并记录
        """
        try:
            # 停止当前定时器
            if self.reminder_timer.isActive():
                self.reminder_timer.stop()
                log_debug("已停止当前提醒定时器")
            
            # 重新设置定时器频率
            self.reminder_timer.start(minutes * 60 * 1000)
            
            # 记录日志
            log_info(f"提醒检查频率已更新为:{minutes}分钟")
        except Exception as e:
            log_error(f"更新提醒频率出错:{str(e)}")
        
    def onTabChanged(self, index):
        """
        标签页切换事件处理
        
        功能: 当用户切换到不同标签页时触发,目前主要处理合同管理标签页的刷新逻辑
             和系统设置页面的密码验证
        
        参数:
            index: 切换到的标签页索引（从0开始）
            - 0: 仪表盘标签页
            - 1: 合同管理标签页
            - 2: 租金管理标签页
            - 3: 提醒设置标签页
            - 4: 基础资料标签页
        
        异常:
            数据库连接或查询异常将被捕获并记录日志
        """
        try:
            log_debug(f"标签页切换到索引: {index}")
            
            # 获取当前标签页文本
            tab_text = self.tabs.tabText(index)
            
            # 系统设置页面密码验证
            if tab_text == '系统设置':
               log_info("切换到系统设置标签页,开始密码验证")
               # 获取系统设置标签页实例
               system_setting_tab = self.tabs.widget(index)
               # 如果尚未认证,则显示认证提示
               if not system_setting_tab.is_authenticated:
                   # 执行密码验证
                   if not system_setting_tab.show_authentication_prompt():
                      log_info("系统设置密码验证失败,返回上一标签页")
                       # 验证失败,切换回之前的标签页
                      QTimer.singleShot(10, lambda: self.tabs.setCurrentIndex(self.last_tab_index))
                      return
                   else:
                       log_info("系统设置密码验证成功")
            
            # 记录当前标签页索引
            self.last_tab_index = index
            
            # 合同管理标签页的索引是1（从0开始）
            if index == 1:
                # 重新加载合同数据
                log_info("切换到合同管理标签页,开始重新加载合同数据")
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if conn is None:
                    log_error("无法获取数据库连接,重新加载合同数据失败")
                    return
                try:
                    self.contract_tab.loadContracts(conn)
                    log_info("合同数据加载完成")
                finally:
                    DatabaseUtils.close_connection(conn)
            
            # 租金管理标签页的索引是2（从0开始）
            elif index == 2:
                # 重新加载租金记录数据
                log_info("切换到租金管理标签页,开始重新加载租金记录数据")
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if conn is None:
                    log_error("无法获取数据库连接,重新加载租金记录数据失败")
                    return
                try:
                    self.rent_tab.loadRentRecords(conn)
                    log_info("租金记录数据加载完成")
                finally:
                    DatabaseUtils.close_connection(conn)
            # 基础资料标签页的索引是4（从0开始）
            elif index == 4:
                # 重新加载基础资料数据
                log_info("切换到基础资料标签页,开始重新加载基础资料数据")
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if conn is None:
                    log_error("无法获取数据库连接,重新加载基础资料数据失败")
                    return
                try:
                    self.basic_data_tab.setDatabaseConnection(conn)
                    log_info("基础资料数据加载完成")
                finally:
                    DatabaseUtils.close_connection(conn)
        except Exception as e:
            log_error(f"标签页切换处理时出错: {str(e)}")
    
    def checkReminders(self):
        """
        检查提醒事项
        
        功能: 执行所有类型的提醒检查（合同到期、租金到期、逾期租金等）
              直接在该方法中实现提醒检查逻辑
        
        异常:
            检查过程中的异常将被捕获并记录日志
        """
        try:
            log_info("开始执行所有提醒事项检查")
            
            # 实现提醒检查逻辑
            # 1. 检查即将到期的合同
            self.check_expiring_contracts()
            # 2. 检查即将到期的租金
            self.check_upcoming_rent()
            # 3. 检查逾期未付的租金
            self.check_overdue_rent()
            # 4. 更新已逾期未结清的合同状态
            self.checkAndUpdateOverdueContracts()
            
            log_info("提醒事项检查完成")
        except Exception as e:
            log_error(f"检查提醒时出错:{str(e)}")
        
    def check_expiring_contracts(self):
        """
        检查即将到期的合同
        
        功能: 查询所有执行中且在提醒天数内即将到期的合同,并添加到提醒列表
        """
        try:
            from datetime import date, timedelta
            
            today = date.today()
            reminders = []
            
            # 从数据库获取提醒天数设置
            contract_reminder_days, _ = self.getReminderSettings()
            
            # 使用现有的checkContractExpirationReminders方法检查合同到期
            self.checkContractExpirationReminders(today, contract_reminder_days, reminders)
            
            if reminders:
                log_info(f"找到 {len(reminders)} 条即将到期的合同")
                # 这里可以添加显示提醒的逻辑
        except Exception as e:
            log_error(f"检查即将到期合同出错:{str(e)}")
    
    def check_upcoming_rent(self):
        """
        检查即将到期的租金
        
        功能: 查询所有执行中合同的即将到期租金,并添加到提醒列表
        """
        try:
            from datetime import date, timedelta
            from db_utils import DatabaseUtils
            
            today = date.today()
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查即将到期租金失败")
                return
            cursor = conn.cursor()
            
            # 从数据库获取租金提醒天数设置
            _, rent_reminder_days = self.getReminderSettings()
            
            # 计算未来提醒日期
            future_date = today + timedelta(days=rent_reminder_days)
            
            # 查询租金到期提醒
            cursor.execute("""
                SELECT r.contract_no, r.period_end, c.house_no, c.lessee 
                FROM rent_records r 
                JOIN contracts c ON r.contract_no = c.contract_no
                WHERE c.status = '执行中' AND r.period_end <= ?
                ORDER BY r.period_end ASC
            """, (future_date.isoformat(),))
            
            rent_reminders = cursor.fetchall()
            
            if rent_reminders:
                log_info(f"找到 {len(rent_reminders)} 条即将到期的租金记录")
                # 这里可以添加显示提醒的逻辑
        except Exception as e:
            log_error(f"检查即将到期租金出错:{str(e)}")
    
    def check_overdue_rent(self):
        """
        检查逾期未付的租金
        
        功能: 查询所有执行中合同的逾期未付租金,并添加到提醒列表
        """
        try:
            from datetime import date
            from db_utils import DatabaseUtils
            
            today = date.today()
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查逾期租金失败")
                return
            cursor = conn.cursor()
            
            # 查询逾期未付的租金（到期日早于今天）
            cursor.execute("""
                SELECT r.contract_no, r.period_end, c.house_no, c.lessee 
                FROM rent_records r 
                JOIN contracts c ON r.contract_no = c.contract_no
                WHERE c.status = '执行中' AND r.period_end < ?
                ORDER BY r.period_end ASC
            """, (today.isoformat(),))
            
            overdue_reminders = cursor.fetchall()
            
            if overdue_reminders:
                log_info(f"找到 {len(overdue_reminders)} 条逾期未付的租金记录")
                # 这里可以添加显示提醒的逻辑
        except Exception as e:
            log_error(f"检查逾期租金出错:{str(e)}")
                
    def checkContractExpirationReminders(self, today, reminder_days, reminders):
        """
        检查合同到期提醒
        
        功能: 检查所有执行中的合同是否即将到期,并在到期前指定天数内添加提醒
        
        参数:
            today: 当前日期（date对象）
            reminder_days: 提前提醒的天数
            reminders: 提醒信息列表,用于存储满足条件的提醒（将被方法修改）
        
        实现步骤:
            1. 查询所有状态为'执行中'的合同
            2. 对每个合同计算距离到期的天数
            3. 检查天数是否在提醒范围内（0到reminder_days之间）
            4. 检查今天是否已经为此合同发送过到期提醒
            5. 如果未发送过提醒,则添加到提醒列表并记录到提醒日志
        
        异常:
            数据库查询异常将被捕获并记录日志,但不会中断检查过程
        """
        try:
            from db_utils import DatabaseUtils
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查合同到期提醒失败")
                return
            cursor = conn.cursor()
            
            log_debug(f"开始检查合同到期提醒,提醒提前天数: {reminder_days}")
            cursor.execute("SELECT contract_no, lessee, end_date, monthly_rent FROM contracts WHERE status = '执行中'")
            contracts = cursor.fetchall()
            log_debug(f"共查询到 {len(contracts)} 个执行中的合同")
            
            for contract in contracts:
                contract_no, lessee, end_date_str, monthly_rent = contract
                end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                days_left = (end_date - today).days
                
                # 检查是否在提醒范围内
                if 0 <= days_left <= reminder_days:
                    log_debug(f"合同 {contract_no} 距离到期还有 {days_left} 天,在提醒范围内")
                    # 检查今天是否已经提醒过
                    cursor.execute(
                        "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '合同到期' AND related_info LIKE ? AND reminder_date = ?",
                        (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                    )
                    if cursor.fetchone()[0] == 0:
                        # 添加到提醒列表
                        reminder_info = {
                            'type': '合同到期',
                            'contract_no': contract_no,
                            'lessee': lessee,
                            'days_left': days_left,
                            'end_date': end_date_str,
                            'monthly_rent': monthly_rent if monthly_rent else 0
                        }
                        reminders.append(reminder_info)
                        log_info(f"已添加合同到期提醒: {contract_no} (剩余 {days_left} 天)")
                        
                        # 记录到提醒日志
                        cursor.execute(
                            "INSERT INTO reminder_logs (reminder_type, related_info, reminder_date) VALUES (?, ?, ?)",
                            ('合同到期', f'合同编号:{contract_no},承租方:{lessee},将在{days_left}天后到期', today.strftime('%Y-%m-%d'))
                        )
            conn.commit()
            log_info(f"合同到期提醒检查完成,共添加 {len([r for r in reminders if r['type'] == '合同到期'])} 条提醒")
        except Exception as e:
            log_error(f"检查合同到期提醒时出错: {str(e)}")
            # 发生异常时回滚事务
            try:
                if 'conn' in locals():
                    conn.rollback()
                    log_debug("合同到期提醒检查事务已回滚")
            except:
                pass
        
    def checkRentDueReminders(self, today, reminder_days, reminders):
        """
        检查租金到期提醒
        
        功能: 检查所有执行中的合同的租金支付情况,计算下一次租金到期日,并在到期前指定天数内添加提醒
        
        参数:
            today: 当前日期（date对象）
            reminder_days: 提前提醒的天数
            reminders: 提醒信息列表,用于存储满足条件的提醒（将被方法修改）
        
        实现步骤:
            1. 查询所有状态为'执行中'的合同
            2. 对每个合同,计算下一次租金到期日
               - 如果有租金记录,基于最后一个周期结束日计算
               - 如果没有租金记录,基于合同开始日期计算
            3. 计算距离下一次到期日的天数
            4. 检查天数是否在提醒范围内且未超过合同结束日期
            5. 检查今天是否已经为此合同发送过租金到期提醒
            6. 如果未发送过提醒,则添加到提醒列表并记录到提醒日志
        
        异常:
            数据库查询异常将被捕获并记录日志,但不会中断检查过程
        """
        try:
            from db_utils import DatabaseUtils
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查租金到期提醒失败")
                return
            cursor = conn.cursor()
            
            log_debug(f"开始检查租金到期提醒,提醒提前天数: {reminder_days}")
            # 获取所有执行中的合同
            cursor.execute("SELECT contract_no, lessee, payment_method, monthly_rent, start_date, end_date FROM contracts WHERE status = '执行中'")
            contracts = cursor.fetchall()
            log_debug(f"共查询到 {len(contracts)} 个执行中的合同")
            
            for contract in contracts:
                contract_no, lessee, payment_method, monthly_rent, start_date_str, end_date_str = contract
                log_debug(f"处理合同: {contract_no},承租方: {lessee}")
                
                # 获取该合同的最新租金记录
                cursor.execute(
                    "SELECT MAX(period_end) FROM rent_records WHERE contract_no = ?",
                    (contract_no,)
                )
                last_period_end = cursor.fetchone()[0]
                log_debug(f"合同 {contract_no} 的最后租金记录周期结束日: {last_period_end}")
                
                # 计算下一次租金到期日
                next_due_date = None
                
                if last_period_end:
                    # 如果有租金记录,基于最后一个周期结束日计算
                    last_period_end_date = datetime.strptime(last_period_end, '%Y-%m-%d').date()
                    
                    # 根据支付方式计算下一次到期日
                    if payment_method == '月付':
                        next_due_date = last_period_end_date + timedelta(days=30)
                    elif payment_method == '季付':
                        next_due_date = last_period_end_date + timedelta(days=90)
                    elif payment_method == '半年付':
                        next_due_date = last_period_end_date + timedelta(days=180)
                    elif payment_method == '年付':
                        next_due_date = last_period_end_date + timedelta(days=365)
                else:
                    # 如果没有租金记录,基于合同开始日期计算
                    start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
                    next_due_date = start_date
                    log_debug(f"合同 {contract_no} 无租金记录,基于开始日期计算到期日")
                
                if next_due_date:
                    days_until_due = (next_due_date - today).days
                    end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                    log_debug(f"合同 {contract_no} 下一次租金到期日: {next_due_date},距离今天还有 {days_until_due} 天")
                    
                    # 检查是否在提醒范围内且未超过合同结束日期
                    if 0 <= days_until_due <= reminder_days and next_due_date <= end_date:
                        log_debug(f"合同 {contract_no} 租金将在 {days_until_due} 天后到期,在提醒范围内")
                        # 检查今天是否已经提醒过
                        cursor.execute(
                            "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '租金到期' AND related_info LIKE ? AND reminder_date = ?",
                            (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                        )
                        if cursor.fetchone()[0] == 0:
                            # 添加到提醒列表
                            reminder_info = {
                                'type': '租金到期',
                                'contract_no': contract_no,
                                'lessee': lessee,
                                'days_left': days_until_due,
                                'due_date': next_due_date.strftime('%Y-%m-%d'),
                                'payment_method': payment_method,
                                'monthly_rent': monthly_rent if monthly_rent else 0
                            }
                            reminders.append(reminder_info)
                            log_info(f"已添加租金到期提醒: {contract_no} (剩余 {days_until_due} 天)")
                            
                            # 记录到提醒日志
                            cursor.execute(
                                "INSERT INTO reminder_logs (reminder_type, related_info, reminder_date) VALUES (?, ?, ?)",
                                ('租金到期', f'合同编号:{contract_no},承租方:{lessee},租金将在{days_until_due}天后到期', today.strftime('%Y-%m-%d'))
                            )
            conn.commit()
            log_info(f"租金到期提醒检查完成,共添加 {len([r for r in reminders if r['type'] == '租金到期'])} 条提醒")
        except Exception as e:
            log_error(f"检查租金到期提醒时出错: {str(e)}")
            # 发生异常时回滚事务
            try:
                if 'conn' in locals():
                    conn.rollback()
                    log_debug("租金到期提醒检查事务已回滚")
            except:
                pass
        
    def checkOverdueReminders(self, today, reminders):
        """
        检查合同逾期提醒
        
        功能: 检查所有状态为'执行中'的合同是否已逾期（超过合同结束日期）,并添加逾期提醒
        
        参数:
            today: 当前日期（date对象）
            reminders: 提醒信息列表,用于存储满足条件的提醒（将被方法修改）
        
        实现步骤:
            1. 查询所有状态为'执行中'的合同
            2. 对每个合同,计算距离合同结束日期的逾期天数
            3. 检查是否已逾期（逾期天数>0）
            4. 检查今天是否已经为此合同发送过逾期提醒
            5. 如果未发送过提醒,则添加到提醒列表并记录到提醒日志
        
        异常:
            数据库查询异常将被捕获并记录日志,但不会中断检查过程
        """
        try:
            from db_utils import DatabaseUtils
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查合同逾期提醒失败")
                return
            cursor = conn.cursor()
            
            log_debug("开始检查合同逾期提醒")
            # 检查已到期的合同
            cursor.execute("SELECT contract_no, lessee, end_date FROM contracts WHERE status = '执行中'")
            contracts = cursor.fetchall()
            log_debug(f"共查询到 {len(contracts)} 个执行中的合同用于逾期检查")
            
            for contract in contracts:
                contract_no, lessee, end_date_str = contract
                log_debug(f"检查合同逾期情况: {contract_no},承租方: {lessee}")
                end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                days_overdue = (today - end_date).days
                log_debug(f"合同 {contract_no} 结束日期: {end_date},逾期天数: {days_overdue}")
                
                if days_overdue > 0:
                    log_debug(f"合同 {contract_no} 已逾期 {days_overdue} 天")
                    # 检查今天是否已经提醒过
                    cursor.execute(
                        "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '合同逾期' AND related_info LIKE ? AND reminder_date = ?",
                        (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                    )
                    if cursor.fetchone()[0] == 0:
                        # 添加到提醒列表
                        reminder_info = {
                            'type': '合同逾期',
                            'contract_no': contract_no,
                            'lessee': lessee,
                            'days_overdue': days_overdue,
                            'end_date': end_date_str
                        }
                        reminders.append(reminder_info)
                        log_info(f"已添加合同逾期提醒: {contract_no} (逾期 {days_overdue} 天)")
                        
                        # 记录到提醒日志
                        cursor.execute(
                            "INSERT INTO reminder_logs (reminder_type, related_info, reminder_date) VALUES (?, ?, ?)",
                            ('合同逾期', f'合同编号:{contract_no},承租方:{lessee},已逾期{days_overdue}天', today.strftime('%Y-%m-%d'))
                        )
            conn.commit()
            log_info(f"合同逾期提醒检查完成,共添加 {len([r for r in reminders if r['type'] == '合同逾期'])} 条提醒")
        except Exception as e:
            log_error(f"检查合同逾期提醒时出错: {str(e)}")
            # 发生异常时回滚事务
            try:
                if 'conn' in locals():
                    conn.rollback()
                    log_debug("合同逾期提醒检查事务已回滚")
            except:
                pass
        
    def showCombinedReminders(self, reminders):
        """
        合并显示各类提醒信息
        
        功能: 将不同类型的提醒信息（合同逾期、合同到期、租金到期）合并显示在一个消息框中,
             按照紧急程度排序,并提供"查看详情"功能切换到提醒标签页
        
        参数:
            reminders: 提醒信息列表,包含各类提醒的详细信息
        
        实现步骤:
            1. 按提醒类型（合同到期、租金到期、合同逾期）进行分组
            2. 按紧急程度对每组提醒进行排序:
               - 合同到期/租金到期:剩余天数越少越紧急
               - 合同逾期:逾期天数越多越紧急
            3. 构建消息内容,按优先级从高到低显示（逾期提醒 > 合同到期 > 租金到期）
            4. 创建消息框,添加"查看详情"和"确定"按钮
            5. 处理用户响应,点击"查看详情"时切换到提醒标签页
        
        异常:
            消息框显示过程中的异常会被内部处理,不会影响系统正常运行
        """
        try:
            log_info(f"开始显示合并提醒信息,共 {len(reminders)} 条提醒")
            if not reminders:
                log_debug("没有待显示的提醒信息")
                return
            
            # 按类型分组并排序
            contract_expiration_reminders = []
            rent_due_reminders = []
            overdue_reminders = []
            
            for reminder in reminders:
                if reminder['type'] == '合同到期':
                    contract_expiration_reminders.append(reminder)
                elif reminder['type'] == '租金到期':
                    rent_due_reminders.append(reminder)
                elif reminder['type'] == '合同逾期':
                    overdue_reminders.append(reminder)
            
            log_debug(f"提醒类型分布 - 合同逾期: {len(overdue_reminders)} 条, 合同到期: {len(contract_expiration_reminders)} 条, 租金到期: {len(rent_due_reminders)} 条")
            
            # 按紧急程度排序
            contract_expiration_reminders.sort(key=lambda x: x['days_left'])  # 剩余天数越少越紧急
            rent_due_reminders.sort(key=lambda x: x['days_left'])  # 剩余天数越少越紧急
            overdue_reminders.sort(key=lambda x: -x['days_overdue'])  # 逾期天数越多越紧急
            
            # 构建消息内容
            message = """
有新的提醒需要您处理:

"""
            
            # 先显示逾期提醒（优先级最高）
            if overdue_reminders:
                message += "⚠️ 合同逾期提醒\n"
                for reminder in overdue_reminders:
                    message += f"  - 合同编号:{reminder['contract_no']},承租方:{reminder['lessee']},已逾期{reminder['days_overdue']}天\n"
                message += "\n"
            
            # 再显示合同到期提醒
            if contract_expiration_reminders:
                message += "📅 合同到期提醒\n"
                for reminder in contract_expiration_reminders:
                    message += f"  - 合同编号:{reminder['contract_no']},承租方:{reminder['lessee']},将在{reminder['days_left']}天后到期\n"
                message += "\n"
            
            # 最后显示租金到期提醒
            if rent_due_reminders:
                message += "💸 租金到期提醒\n"
                for reminder in rent_due_reminders:
                    message += f"  - 合同编号:{reminder['contract_no']},承租方:{reminder['lessee']},租金将在{reminder['days_left']}天后到期\n"
            
            # 创建消息框,添加查看详情按钮
            msg_box = QMessageBox()
            msg_box.setWindowTitle("系统提醒")
            msg_box.setText(message)
            msg_box.setIcon(QMessageBox.Information)
            
            # 添加查看详情按钮和确定按钮
            details_button = msg_box.addButton("查看详情", QMessageBox.ActionRole)
            ok_button = msg_box.addButton("确定", QMessageBox.AcceptRole)
            
            # 执行消息框并获取用户的响应
            msg_box.exec_()
            
            # 如果用户点击了查看详情按钮,切换到提醒标签页
            if msg_box.clickedButton() == details_button:
                log_info("用户点击了'查看详情'按钮,正在切换到提醒标签页")

            else:
                log_debug("用户点击了'确定'按钮或关闭了提醒窗口")
        except Exception as e:
            log_error(f"显示合并提醒信息时出错: {str(e)}")
    
    def checkAndUpdateExpiredContracts(self):
        """
        检查并更新过期合同
        
        功能: 检查数据库中合同表内end_date列的所有日期值,若存在日期值小于或等于当前日期的记录,
              且其payment_status的值为"已结清",则将这些记录对应的status列的值更新为"已完成",并弹出提示消息
        
        实现步骤:
            1. 获取当前日期
            2. 查询数据库中end_date小于或等于当前日期且payment_status为"已结清"的合同记录
            3. 将这些合同的status更新为"已完成"
            4. 如果有符合条件的合同,显示提示消息
            5. 提交数据库事务
        
        异常:
            数据库操作异常将被捕获并记录日志
        """
        try:
            from datetime import date
            from PyQt5.QtWidgets import QMessageBox
            from db_utils import DatabaseUtils
            
            # 获取最新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查过期合同失败")
                return
            
            cursor = conn.cursor()
            
            # 获取当前日期
            today = date.today().isoformat()
            log_debug(f"检查过期合同,当前日期: {today}")
            
            # 查询过期且已结清的合同
            cursor.execute("""
                SELECT contract_no, house_no 
                FROM contracts 
                WHERE status = '执行中' AND end_date <= ? AND payment_status = '已结清'
                ORDER BY end_date ASC
            """, (today,))
            expired_contracts = cursor.fetchall()
            
            if expired_contracts:
                log_info(f"发现 {len(expired_contracts)} 个已过期且已结清的合同")
                
                # 更新过期且已结清的合同状态
                cursor.execute("""
                    UPDATE contracts 
                    SET status = '已完成' 
                    WHERE status = '执行中' AND end_date <= ? AND payment_status = '已结清'
                """, (today,))
                conn.commit()
                log_info(f"已将 {len(expired_contracts)} 个过期合同状态更新为'已完成'")
                
                # 构建提示消息
                message = f"今天（{today}）,有如下合同今天到期!\n"
                for i, contract in enumerate(expired_contracts, 1):
                    message += f"{i}. 合同编号: {contract[0]}, 房屋编号: {contract[1]}\n"
                
                # 显示提示消息
                QMessageBox.information(self, "合同到期提醒", message)
            else:
                log_debug("未发现过期合同")
                
        except Exception as e:
            log_error(f"检查并更新过期合同时出错: {str(e)}")
            # 发生异常时回滚事务
            try:
                if 'conn' in locals():
                    conn.rollback()
            except:
                pass
        finally:
            # 关闭连接
            if 'conn' in locals():
                DatabaseUtils.close_connection(conn)
                
    def checkAndUpdateOverdueContracts(self):
        """
        检查并更新逾期未结清合同
        
        功能: 检查数据库中合同表内end_date列的所有日期值,若存在日期值小于或等于当前日期的记录,
              且其payment_status的值为"未结清",则将这些记录对应的status列的值更新为"已逾期",并弹出提示消息
        
        实现步骤:
            1. 获取当前日期
            2. 查询数据库中end_date小于或等于当前日期且payment_status为"未结清"的合同记录
            3. 将这些合同的status更新为"已逾期"
            4. 如果有符合条件的合同,显示提示消息
            5. 提交数据库事务
        
        异常:
            数据库操作异常将被捕获并记录日志
        """
        try:
            from datetime import date
            from PyQt5.QtWidgets import QMessageBox
            from db_utils import DatabaseUtils
            
            # 获取最新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,检查逾期合同失败")
                return
            
            cursor = conn.cursor()
            
            # 获取当前日期
            today = date.today().isoformat()
            log_debug(f"检查逾期合同,当前日期: {today}")
            
            # 查询过期且未结清的合同
            cursor.execute("""
                SELECT contract_no, house_no 
                FROM contracts 
                WHERE status = '执行中' AND end_date <= ? AND payment_status = '未结清'
                ORDER BY end_date ASC
            """, (today,))
            overdue_contracts = cursor.fetchall()
            
            if overdue_contracts:
                log_info(f"发现 {len(overdue_contracts)} 个已逾期且未结清的合同")
                
                # 更新逾期且未结清的合同状态
                cursor.execute("""
                    UPDATE contracts 
                    SET status = '已逾期' 
                    WHERE status = '执行中' AND end_date <= ? AND payment_status = '未结清'
                """, (today,))
                conn.commit()
                log_info(f"已将 {len(overdue_contracts)} 个逾期合同状态更新为'已逾期'")
                
                # 构建提示消息
                message = f"今天（{today}）,发现以下合同已逾期且未结清!\n"
                message += f"共更新了 {len(overdue_contracts)} 个合同状态为'已逾期'\n\n"
                for i, contract in enumerate(overdue_contracts, 1):
                    message += f"{i}. 合同编号: {contract[0]}, 房屋编号: {contract[1]}\n"
                message += "\n请及时处理这些逾期合同!"
                
                # 显示提示消息
                QMessageBox.warning(self, "合同逾期提醒", message)
            else:
                log_debug("未发现逾期且未结清的合同")
                
        except Exception as e:
            log_error(f"检查并更新逾期合同时出错: {str(e)}")
            # 发生异常时回滚事务
            try:
                if 'conn' in locals():
                    conn.rollback()
            except:
                pass
        finally:
            # 关闭连接
            if 'conn' in locals():
                DatabaseUtils.close_connection(conn)
    
    def refreshAllData(self):
        """
        刷新所有数据到各个功能标签页
        
        功能: 当数据库切换后,重新加载所有模块的数据,确保使用新数据库
        
        加载顺序:
            1. 检查并更新过期合同
            2. 仪表盘数据
            3. 合同数据
            4. 租金记录数据
            5. 房屋基础数据
            6. 租户基础数据
            7. 房东基础数据
        """
        from db_utils import DatabaseUtils
        
        try:
            log_info("开始刷新系统所有数据")
            
            # 获取新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,刷新数据失败")
                return
            
            # 首先检查并更新过期合同和逾期未结清合同
            self.checkAndUpdateExpiredContracts()
            self.checkAndUpdateOverdueContracts()
            
            # 刷新所有数据到各个标签页
            log_debug("开始刷新仪表盘数据")
            self.loadDashboardData()
            log_debug("仪表盘数据刷新完成")
            
            log_debug("开始刷新合同数据")
            self.contract_tab.loadContracts(conn)
            log_debug("合同数据刷新完成")
            
            log_debug("开始刷新租金记录数据")
            self.rent_tab.loadRentRecords(conn)
            log_debug("租金记录数据刷新完成")
            
            log_debug("开始刷新基础资料数据")
            self.basic_data_tab.refreshAllModules()
            log_debug("基础资料数据刷新完成")
            
            # 关闭连接
            DatabaseUtils.close_connection(conn)
            
            log_info("系统所有数据刷新完成")
        except Exception as e:
            log_error(f"刷新系统数据时出错: {str(e)}")
            try:
                if 'conn' in locals():
                    DatabaseUtils.close_connection(conn)
            except:
                pass
    
    def loadAllData(self):
        """
        加载所有数据到各个功能标签页
        
        功能: 依次调用各个标签页的数据加载方法,初始化系统所有数据
        
        加载顺序:
            1. 检查并更新过期合同
            2. 仪表盘数据
            3. 合同数据
            4. 租金记录数据
            5. 提醒设置数据
            6. 房屋基础数据
            7. 租户基础数据
            8. 房东基础数据
        
        异常:
            数据加载过程中的异常会被捕获并记录日志,但不会中断系统启动
        """
        from db_utils import DatabaseUtils
        
        try:
            log_info("开始加载系统所有数据")
            
            # 获取数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("无法获取数据库连接,加载数据失败")
                return
                
            # 首先检查并更新过期合同和逾期未结清合同
            self.checkAndUpdateExpiredContracts()
            self.checkAndUpdateOverdueContracts()
            # 加载所有数据到各个标签页
            log_debug("开始加载仪表盘数据")
            self.loadDashboardData()
            log_debug("仪表盘数据加载完成")
            
            log_debug("开始加载合同数据")
            self.contract_tab.loadContracts(conn)
            log_debug("合同数据加载完成")
            
            log_debug("开始加载租金记录数据")
            self.rent_tab.loadRentRecords(conn)
            log_debug("租金记录数据加载完成")
            
            log_debug("开始加载基础资料数据")
            self.basic_data_tab.setDatabaseConnection(conn)
            log_debug("基础资料数据加载完成")
            
            # 关闭连接
            DatabaseUtils.close_connection(conn)
            
            log_info("系统所有数据加载完成")
        except Exception as e:
            log_error(f"加载系统数据时出错: {str(e)}")
            try:
                if 'conn' in locals():
                    DatabaseUtils.close_connection(conn)
            except:
                pass
    
    def getReminderSettings(self):
        """
        从数据库获取提醒设置
        
        返回:
            tuple: (contract_reminder_days, rent_reminder_days),分别为合同到期提醒天数和租金到期提醒天数
        """
        # 从db_utils导入DatabaseUtils类
        from db_utils import DatabaseUtils
        conn = None
        cursor = None
        try:
            # 使用DatabaseUtils获取最新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("获取数据库连接失败")
                return 30, 7
                
            cursor = conn.cursor()
            cursor.execute("SELECT contract_reminder_days, rent_reminder_days FROM reminder_settings LIMIT 1")
            result = cursor.fetchone()
            if result:
                return result[0], result[1]
            else:
                # 如果没有记录,返回默认值
                return 30, 7
        except Exception as e:
            log_error(f"获取提醒设置时出错: {str(e)}")
            # 出错时返回默认值
            return 30, 7
        finally:
            # 使用DatabaseUtils关闭连接
            if conn:
                DatabaseUtils.close_connection(conn)
                cursor = None
                conn = None

    def loadDashboardData(self):
        """
        加载仪表盘数据
        
        功能: 从数据库获取合同总数、活跃合同数、应收租金总额和已收租金总额等关键指标数据,并更新仪表盘显示
        同时调用loadRentTrendData方法加载租金收入趋势数据,以及加载合同到期和租金到期提醒数据
        
        实现步骤:
            1. 查询数据库获取总合同数量
            2. 查询数据库获取状态为'执行中'的活跃合同数量
            3. 计算当前所有执行中合同的应收租金总额
            4. 统计所有已收租金记录的总金额
            5. 调用dashboard_tab的updateDashboard方法更新仪表盘显示
            6. 调用loadRentTrendData方法加载并更新租金收入趋势数据
            7. 调用loadReminderData方法加载并更新合同到期和租金到期提醒数据
            8. 获取合同到期明细数据并更新到仪表盘
        
        异常:
            数据库查询异常将被捕获并记录日志,同时设置默认值确保仪表盘正常显示
        """
        # 从db_utils导入DatabaseUtils类
        from db_utils import DatabaseUtils
        conn = None
        cursor = None
        try:
            log_debug("开始加载仪表盘数据")
            
            # 使用DatabaseUtils获取最新的数据库连接
            conn = DatabaseUtils.get_connection()
            if conn is None:
                log_error("获取数据库连接失败")
                return
                
            cursor = conn.cursor()
            
            # 总合同数
            try:
                cursor.execute("SELECT COUNT(*) FROM contracts")
                total_contracts = cursor.fetchone()[0]
                log_debug(f"总合同数: {total_contracts}")
            except sqlite3.Error as e:
                total_contracts = 0
                log_error(f"查询总合同数时出错: {str(e)}")
            
            # 活跃合同数
            try:
                cursor.execute("SELECT COUNT(*) FROM contracts WHERE status = '执行中'")
                active_contracts = cursor.fetchone()[0]
                log_debug(f"活跃合同数: {active_contracts}")
            except sqlite3.Error as e:
                active_contracts = 0
                log_error(f"查询活跃合同数时出错: {str(e)}")
            
            # 已完成合同数
            try:
                cursor.execute("SELECT COUNT(*) FROM contracts WHERE status = '已完成'")
                completed_contracts = cursor.fetchone()[0]
                log_debug(f"已完成合同数: {completed_contracts}")
            except sqlite3.Error as e:
                completed_contracts = 0
                log_error(f"查询已完成合同数时出错: {str(e)}")
            
            # 已逾期合同数
            try:
                from datetime import date
                today = date.today().isoformat()
                cursor.execute("SELECT COUNT(*) FROM contracts WHERE status = '已逾期' OR (status = '执行中' AND end_date < ?)", (today,))
                overdue_contracts = cursor.fetchone()[0]
                log_debug(f"已逾期合同数: {overdue_contracts}")
            except sqlite3.Error as e:
                overdue_contracts = 0
                log_error(f"查询已逾期合同数时出错: {str(e)}")
            
            # 年度租金总额（修正逻辑:所有合同的annual_rent字段合计）
            try:
                cursor.execute("SELECT SUM(annual_rent) FROM contracts")
                result = cursor.fetchone()[0]
                annual_rent = result if result else 0
                log_debug(f"年度租金总额: {annual_rent}")
            except sqlite3.Error as e:
                annual_rent = 0
                log_error(f"计算年度租金总额时出错: {str(e)}")
            
            # 已收租金总额（修正逻辑:rent_records表中所有amount字段合计）
            try:
                cursor.execute("SELECT SUM(amount) FROM rent_records")
                result = cursor.fetchone()[0]
                received_rent = result if result else 0
                log_debug(f"已收租金总额: {received_rent}")
            except sqlite3.Error as e:
                received_rent = 0
                log_error(f"计算已收租金总额时出错: {str(e)}")
            
            # 应收租金总额（年度租金总额减去已收租金总额）
            try:
                receivable_rent = max(0, annual_rent - received_rent)  # 确保结果不为负数
                log_debug(f"应收租金总额: {receivable_rent}")
            except Exception as e:
                receivable_rent = 0
                log_error(f"计算应收租金总额时出错: {str(e)}")
            
            # 押金总金额
            try:
                cursor.execute("SELECT SUM(deposit) FROM contracts")
                result = cursor.fetchone()[0]
                total_deposit = result if result else 0
                log_debug(f"押金总金额: {total_deposit}")
            except Exception as e:
                total_deposit = 0
                log_error(f"计算押金总金额时出错: {str(e)}")
            
            # 获取合同到期明细数据（符合条件:执行中、未来30天内到期或已逾期、未结清）
            contract_expiry_details = []
            try:
                from datetime import date, timedelta
                today = date.today()
                # 从数据库获取合同到期提醒天数
                contract_reminder_days, _ = self.getReminderSettings()
                future_date = today + timedelta(days=contract_reminder_days)  # 使用数据库中的设置
                
                # 获取所有执行中或已逾期且到期日期在未来N天内或已逾期的合同,同时获取年租金总额
                cursor.execute("""
                    SELECT contract_no, end_date, house_no, lessee, annual_rent 
                    FROM contracts 
                    WHERE (status = '执行中' OR status = '已逾期') AND end_date BETWEEN ? AND ?
                    ORDER BY end_date ASC
                """, ((today - timedelta(days=365)).isoformat(), future_date.isoformat()))  # 包含过去一年内的日期以捕获逾期合同
                
                contracts = cursor.fetchall()
                
                for contract in contracts:
                    contract_no, end_date, house_no, lessee, contract_annual_rent = contract
                    contract_end = date.fromisoformat(end_date)
                    
                    # 只保留未来30天内或已逾期的合同
                    if contract_end > future_date:
                        continue
                    
                    # 判断租金是否结清（与合同表格中收款情况字段计算逻辑保持一致）
                    is_paid_up = False
                    
                    try:
                        # 获取年租金总额
                        annual_rent_value = float(contract_annual_rent) if contract_annual_rent else 0
                        annual_rent_value = round(annual_rent_value)  # 四舍五入,保留整数
                        
                        # 查询实际已支付的金额
                        cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
                        result = cursor.fetchone()
                        contract_received_rent = float(result[0]) if result and result[0] is not None else 0
                        contract_received_rent = round(contract_received_rent)  # 四舍五入,保留整数
                        
                        # 计算剩余租金（年租金总额 - 已收总租金）
                        remaining_rent = annual_rent_value - contract_received_rent
                        
                        # 判断收款情况是否为未结清
                        # 与合同表格中收款情况字段计算逻辑保持一致:remaining_rent != 0 表示未结清
                        if remaining_rent == 0:
                            is_paid_up = True
                    except Exception as e:
                        log_error(f"计算合同 {contract_no} 收款情况时出错: {str(e)}")
                        continue
                    
                    # 只添加未结清的合同（收款情况为"未结清"）
                    if not is_paid_up:
                        contract_expiry_details.append({
                            'contract_no': contract_no,
                            'end_date': end_date,
                            'house_no': house_no,
                            'lessee': lessee
                        })
                
                log_debug(f"找到 {len(contract_expiry_details)} 条收款情况为未结清且即将到期的合同")
            except Exception as e:
                log_error(f"获取合同到期明细时出错: {str(e)}")
            
            # 更新仪表盘
            try:
                self.dashboard_tab.updateDashboard(total_contracts, active_contracts, completed_contracts, overdue_contracts, receivable_rent, received_rent, annual_rent, total_deposit, contract_expiry_details)
                log_info("仪表盘数据更新完成")
            except Exception as e:
                log_error(f"更新仪表盘显示时出错: {str(e)}")
            
            # 加载租金收入趋势数据
            self.loadRentTrendData()
            
            # 加载提醒数据
            self.loadReminderData()
        except Exception as e:
            log_error(f"加载仪表盘数据时出错: {str(e)}")
        finally:
            # 使用DatabaseUtils关闭连接
            if conn:
                DatabaseUtils.close_connection(conn)
                cursor = None
                conn = None
    
    def loadReminderData(self):
        """
        加载合同到期提醒和租金到期提醒数据
        
        功能: 从数据库获取未来30天内（含已逾期）到期的合同和租金记录,并更新仪表盘上的提醒显示
        
        实现步骤:
            1. 查询未来30天内（含已逾期）到期的合同
            2. 执行合同表和租金记录表的联合查询,获取两类租金记录:
               a. 租金记录表中所属期间截止日期在未来30天内或已逾期的记录
               b. 合同表中存在但租金记录表中无对应记录的执行中合同
            3. 调用dashboard_tab的updateReminders方法更新提醒显示
        
        异常:
            数据库查询异常将被捕获并记录日志,同时设置空列表确保提醒模块正常显示
        """
        conn = None
        cursor = None
        try:
            log_debug("开始加载提醒数据")
            
            # 导入必要的模块
            from datetime import date, timedelta
            
            # 使用DatabaseUtils获取最新连接
            conn = DatabaseUtils.get_connection()
            if not conn:
                log_error("无法获取数据库连接")
                return
            cursor = conn.cursor()
            
            # 获取当前日期
            today = date.today()
            
            # 从数据库获取提醒天数设置
            contract_reminder_days, rent_reminder_days = self.getReminderSettings()
            
            # 查询未来N天内到期的合同（包括已逾期的）
            contract_reminders = []
            try:
                future_date = today + timedelta(days=contract_reminder_days)  # 使用数据库中的设置
                
                # 查询状态为'执行中',且到期日期在今天到N天后之间（或已逾期）的合同
                # 增加house_no和lessee字段
                cursor.execute("""
                    SELECT contract_no, end_date, house_no, lessee FROM contracts 
                    WHERE status = '执行中' AND end_date BETWEEN ? AND ?
                    ORDER BY end_date ASC
                """, ((today - timedelta(days=365)).isoformat(), future_date.isoformat()))  # 包含过去一年内的日期以捕获逾期合同
                
                results = cursor.fetchall()
                for row in results:
                    contract_reminders.append({
                        'contract_no': row[0],
                        'expiry_date': row[1],
                        'house_no': row[2],
                        'lessee': row[3]
                    })
                
                # 过滤只保留未来N天内（含已逾期）的合同
                contract_reminders = [reminder for reminder in contract_reminders 
                                     if date.fromisoformat(reminder['expiry_date']) <= future_date]
                
                log_debug(f"找到 {len(contract_reminders)} 条合同到期提醒")
            except Exception as e:
                log_error(f"查询合同到期提醒时出错: {str(e)}")
            
            # 查询未来30天内到期的租金（包括已逾期的）
            rent_reminders = []
            try:
                # 使用从数据库获取的租金到期提醒天数
                future_date = today + timedelta(days=rent_reminder_days)
                
                # 查询1: 从租金记录表中查询所属期间截止日期在提醒范围内或已逾期的记录
                # 精确筛选:所属期间截止日期在当前日期未来N天内（含N天当日）或已逾期的记录
                cursor.execute("""
                    SELECT r.contract_no, r.period_end, c.house_no, c.lessee 
                    FROM rent_records r 
                    JOIN contracts c ON r.contract_no = c.contract_no
                    WHERE c.status = '执行中' AND r.period_end <= ?
                    ORDER BY r.period_end ASC
                """, (future_date.isoformat(),))  # 根据数据库中的提醒天数设置
                
                rent_record_results = cursor.fetchall()
                for row in rent_record_results:
                    # 确保记录日期符合条件:在当前日期未来30天内（含30天当日）或已逾期
                    period_end_date = date.fromisoformat(row[1])
                    if period_end_date <= future_date:
                        rent_reminders.append({
                            'contract_no': row[0],
                            'due_date': row[1],
                            'house_no': row[2],
                            'lessee': row[3]
                        })
                
                # 查询2: 查找合同表中存在但租金记录表中无对应记录的执行中合同
                cursor.execute("""
                    SELECT c.contract_no, c.house_no, c.lessee, c.start_date 
                    FROM contracts c 
                    LEFT JOIN rent_records r ON c.contract_no = r.contract_no
                    WHERE c.status = '执行中' AND r.contract_no IS NULL
                    ORDER BY c.contract_no ASC
                """)
                
                missing_rent_results = cursor.fetchall()
                for row in missing_rent_results:
                    # 对于没有租金记录的合同,使用合同的start_date作为到期日期
                    rent_reminders.append({
                        'contract_no': row[0],
                        'due_date': row[3] if row[3] else "未设置租金记录",
                        'house_no': row[1],
                        'lessee': row[2]
                    })
                
                # 处理重复合同编号,只保留到期日期最晚的记录
                unique_reminders = {}
                for reminder in rent_reminders:
                    contract_no = reminder['contract_no']
                    due_date = reminder['due_date']
                    
                    # 如果合同编号不存在或当前记录的到期日期更新
                    if contract_no not in unique_reminders or \
                       (due_date != "未设置租金记录" and \
                        unique_reminders[contract_no]['due_date'] != "未设置租金记录" and \
                        due_date > unique_reminders[contract_no]['due_date']) or \
                       (due_date != "未设置租金记录" and unique_reminders[contract_no]['due_date'] == "未设置租金记录"):
                        unique_reminders[contract_no] = reminder
                
                # 将去重后的记录转换回列表
                rent_reminders = list(unique_reminders.values())
                
                # 过滤只保留收款情况为"未结清"的记录
                filtered_reminders = []
                for reminder in rent_reminders:
                    contract_no = reminder['contract_no']
                    is_paid_up = False
                    
                    try:
                        # 获取合同年租金总额
                        cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
                        result = cursor.fetchone()
                        annual_rent_value = float(result[0]) if result and result[0] is not None else 0
                        annual_rent_value = round(annual_rent_value)  # 四舍五入,保留整数
                        
                        # 查询实际已支付的金额
                        cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
                        result = cursor.fetchone()
                        contract_received_rent = float(result[0]) if result and result[0] is not None else 0
                        contract_received_rent = round(contract_received_rent)  # 四舍五入,保留整数
                        
                        # 计算剩余租金（年租金总额 - 已收总租金）
                        remaining_rent = annual_rent_value - contract_received_rent
                        
                        # 判断收款情况是否为未结清
                        # 与合同表格中收款情况字段计算逻辑保持一致:remaining_rent != 0 表示未结清
                        if remaining_rent == 0:
                            is_paid_up = True
                    except Exception as e:
                        log_error(f"计算合同 {contract_no} 收款情况时出错: {str(e)}")
                        continue
                    
                    # 只添加未结清的记录
                    if not is_paid_up:
                        filtered_reminders.append(reminder)
                
                # 更新为过滤后的提醒列表
                rent_reminders = filtered_reminders
                
                # 按到期日期排序（特殊处理"未设置租金记录"的条目,将其放在最后）
                rent_reminders.sort(key=lambda x: x['due_date'] if x['due_date'] != "未设置租金记录" else "9999-12-31")
                
                log_debug(f"找到 {len(rent_reminders)} 条收款情况为未结清的租金到期提醒")
            except Exception as e:
                log_error(f"查询租金到期提醒时出错: {str(e)}")
            
            # 更新提醒显示
            try:
                self.dashboard_tab.updateReminders(rent_reminders)
                log_info("提醒数据更新完成")
            except Exception as e:
                log_error(f"更新提醒显示时出错: {str(e)}")
        except Exception as e:
            log_error(f"加载提醒数据时出错: {str(e)}")
        finally:
            # 使用DatabaseUtils关闭连接
            if conn:
                DatabaseUtils.close_connection(conn)
                cursor = None
                conn = None
    
    def loadRentTrendData(self):
        conn = None
        cursor = None
        """
        加载租金收入趋势数据
        
        功能: 统计最近12个月的应收租金和实际收款金额,并更新趋势图显示
        
        实现步骤:
            1. 生成最近12个月的月份列表（从最早到最新）
            2. 对于每个月,计算该月的应收租金总额(基于执行中的合同)
            3. 对于每个月,计算该月的实际收款总额(基于租金记录)
            4. 调用dashboard_tab的updateRentTrend方法更新趋势图
        
        异常:
            数据库查询异常将被捕获并记录日志,同时设置对应月份数据为0,确保趋势图能够正常显示
        """
        try:
            log_debug("开始加载租金收入趋势数据")
            # 加载租金收入趋势数据
            # 从数据库中统计最近10个月的实际收款数据
            months = []
            receivable = []
            received = []
            
            # 使用DatabaseUtils获取最新连接
            conn = DatabaseUtils.get_connection()
            if not conn:
                log_error("无法获取数据库连接")
                return
            cursor = conn.cursor()
            
            # 获取最近12个月的月份列表
            try:
                today = date.today()
                for i in range(12):
                    # 计算前i个月的日期
                    year = today.year
                    month = today.month - i
                    if month <= 0:
                        year -= 1
                        month += 12
                    months.append(f"{year}-{month:02d}")
                
                # 反转顺序,从最早的月份开始
                months.reverse()
                log_debug(f"生成的月份列表: {months}")
            except Exception as e:
                log_error(f"生成月份列表时出错: {str(e)}")
                # 设置默认的月份列表以确保后续操作能够进行
                months = [f"{date.today().year - (i//12)}-{(date.today().month - i%12 -1) % 12 + 1:02d}" for i in range(12)]
                log_debug(f"使用默认月份列表: {months}")
            
            # 为每个月计算应收金额和已收金额
            if months:
                for month in months:
                    # 计算该月应收租金总额（基于执行中的合同和月租金）
                    try:
                        # 获取该月所有执行中的合同的月租金总和
                        cursor.execute("""
                            SELECT SUM(monthly_rent) 
                            FROM contracts 
                            WHERE status = '执行中' 
                            AND start_date <= ? || '-01' 
                            AND end_date >= ? || '-01'
                        """, (month, month))
                        result = cursor.fetchone()[0]
                        month_receivable = result if result else 0
                        log_debug(f"{month}月应收租金: {month_receivable}")
                    except Exception as e:
                        month_receivable = 0
                        log_error(f"计算{month}应收金额出错: {str(e)}")
                    except Exception as e:
                        month_receivable = 0
                        log_error(f"计算{month}应收金额时发生未知错误: {str(e)}")
                    
                    # 统计该月实际收款金额
                    try:
                        # 从rent_records表中统计该月的收款总额
                        cursor.execute("""
                            SELECT SUM(amount) 
                            FROM rent_records 
                            WHERE receipt_date LIKE ? || '%'
                        """, (month,))
                        result = cursor.fetchone()[0]
                        month_received = result if result else 0
                        log_debug(f"{month}月实际收款: {month_received}")
                    except Exception as e:
                        month_received = 0
                        log_error(f"统计{month}收款金额出错: {str(e)}")
                    except Exception as e:
                        month_received = 0
                        log_error(f"统计{month}收款金额时发生未知错误: {str(e)}")
                    
                    receivable.append(month_receivable)
                    received.append(month_received)
            
            # 更新趋势图
            if months and receivable and received:
                try:
                    self.dashboard_tab.updateRentTrend(months, receivable, received)
                    log_info("租金收入趋势数据加载完成并更新趋势图")
                except Exception as e:
                    log_error(f"更新租金收入趋势图时出错: {str(e)}")
            else:
                log_warning("没有有效的数据用于更新租金收入趋势图")
        except Exception as e:
            log_error(f"加载租金收入趋势数据时出错: {str(e)}")
        finally:
            # 关闭数据库连接
            if conn:
                DatabaseUtils.close_connection(conn)
                cursor = None
                conn = None
    
    def updateDashboard(self):
        """
        更新仪表盘数据
        
        功能: 调用loadDashboardData方法重新加载并更新仪表盘的所有数据
        通常在数据发生变化后调用,确保仪表盘显示最新信息
        """
        try:
            log_info("开始更新仪表盘数据")
            # 更新仪表盘数据
            self.loadDashboardData()
            log_info("仪表盘数据更新完成")
        except Exception as e:
            log_error(f"更新仪表盘数据时出错: {str(e)}")
    
    def closeEvent(self, event):
        """
        窗口关闭事件处理
        
        功能: 当用户关闭主窗口时执行,负责关闭数据库连接并接受关闭事件
        
        参数:
            event: QCloseEvent对象,包含关闭事件的信息
        
        异常:
            数据库关闭异常将被捕获并记录日志,但不会阻止窗口关闭
        """
        try:
            log_info("开始关闭系统资源")
            # 关闭数据库连接
            if hasattr(self, 'conn') and self.conn is not None:
                self.conn.close()
                log_info("数据库连接已关闭")
            event.accept()
            log_info("系统已成功关闭")
        except Exception as e:
            log_error(f"关闭系统资源时出错: {str(e)}")
            # 即使出错也接受关闭事件,确保程序能够退出
            event.accept()

# 基础资料标签页
    def onLogout(self):
        """处理退出登录操作"""
        from user_auth import auth_manager
        
        # 确认退出登录
        reply = QMessageBox.question(
            self,
            '警告',
            '所选数据库文件缺少必要表,继续使用可能导致程序功能异常,是否继续?',
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No
        )
           
        
        if reply == QMessageBox.Yes:
            log_info(f'用户 {auth_manager.current_user} 退出登录')
            auth_manager.logout()
            # 退出应用程序,而不是重新登录
            QApplication.instance().quit()
    
    def onChangePassword(self):
        """处理修改密码操作"""
        from user_auth import auth_manager
        
        if auth_manager.change_password():
            log_info(f'用户 {auth_manager.current_user} 修改了密码')
            # 修改密码后更新用户信息显示
            self.user_info_label.setText(f'当前用户: {auth_manager.current_user} ({auth_manager.current_role})')
    
    def onSwitchUser(self):
        """处理切换用户操作"""
        from user_auth import auth_manager
        
        # 确认切换用户
        reply = QMessageBox.question(
            self,
            '确认切换用户',
            '确定要切换到其他用户吗?',
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            log_info(f'用户 {auth_manager.current_user} 切换用户')
            auth_manager.logout()
            self.reLogin()
    
    def reLogin(self):
        """重新登录功能 - 适用于Windows环境"""
        import subprocess
        
        # 关闭当前窗口
        self.close()
        
        # 在Windows环境下,使用subprocess启动新的应用程序实例
        # 获取当前Python解释器路径和脚本路径
        python = sys.executable
        script_path = sys.argv[0]
        
        # 启动新的应用程序进程
        subprocess.Popen([python, script_path])
        
        # 退出当前进程
        sys.exit(0)

# 导入必要的模块
from user_auth import auth_manager
from operation_logger import record_operation
from db_utils import DatabaseUtils

# 导入新的模块化基础资料页面
from basic_data_main import BasicDataMainPage

class BasicDataTab(BasicDataMainPage):
    """基础资料标签页 - 使用模块化实现"""
    def __init__(self):
        # 调用父类构造函数，但不立即加载数据，因为数据库连接尚未建立
        super().__init__(conn=None)
        self.conn = None  # 数据库连接将在加载数据时设置
        log_info("初始化基础资料标签页")

        # 初始化UI和其他方法都已在父类中实现
        # 所有页面功能已移至父类BasicDataMainPage实现
        # 数据加载和刷新通过setDatabaseConnection和refreshAllModules方法处理
        # Excel导出功能也已移至父类实现

# 仪表盘标签页
class DashboardTab(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        # 应用当前主题样式
        self.applyThemeStyle()
    
    def initUI(self):
        # 创建主布局 - 使用QGridLayout以支持加载指示器
        main_layout = QGridLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        

        
        # 创建搜索和操作按钮区域
        search_layout = QHBoxLayout()
        
        # 创建统计和提醒模块区域
        modules_layout = QHBoxLayout()
        modules_layout.setSpacing(10)  # 设置模块间距
        
        # 创建合同情况框架模块（移至首列位置）
        contract_situation_group = QGroupBox('合同情况')
        contract_situation_layout = QVBoxLayout(contract_situation_group)
        contract_situation_layout.setSpacing(5)  # 设置垂直布局中的间距
        contract_situation_layout.setContentsMargins(10, 10, 10, 10)
        
        # 设置标题字体
        font = QFont()
        font.setPointSize(10)
        font.setBold(True)
        contract_situation_group.setFont(font)
        
        # 创建合同总数子框架
        self.total_contracts_count_card = self.createDashboardModule('合同总数', 'value')
        contract_situation_layout.addWidget(self.total_contracts_count_card)
        
        # 创建执行中合同子框架
        self.active_contracts_count_card = self.createDashboardModule('执行中合同', 'value')
        contract_situation_layout.addWidget(self.active_contracts_count_card)
        
        # 创建已完成合同子框架
        self.completed_contracts_count_card = self.createDashboardModule('已完成合同', 'value')
        contract_situation_layout.addWidget(self.completed_contracts_count_card)
        
        # 创建已逾期合同子框架
        self.overdue_contracts_count_card = self.createDashboardModule('已逾期合同', 'value')
        contract_situation_layout.addWidget(self.overdue_contracts_count_card)
        
        # 将合同情况模块添加到主模块布局中（首列位置）
        modules_layout.addWidget(contract_situation_group, 7)  # 减少30%宽度，使用整数比例
        
        # 创建租金押金框架模块
        rent_deposit_group = QGroupBox('租金押金')
        rent_deposit_layout = QVBoxLayout(rent_deposit_group)
        rent_deposit_layout.setSpacing(5)  # 设置垂直布局中的间距
        rent_deposit_layout.setContentsMargins(10, 10, 10, 10)
        
        # 设置标题字体
        font = QFont()
        font.setPointSize(10)
        font.setBold(True)
        rent_deposit_group.setFont(font)
        
        # 创建年度租金总额子框架
        self.annual_rent_card = self.createDashboardModule('年度租金总额', 'value')
        rent_deposit_layout.addWidget(self.annual_rent_card)
        
        # 创建已收租金总额子框架
        self.received_total_rent_card = self.createDashboardModule('已收租金总额', 'value')
        rent_deposit_layout.addWidget(self.received_total_rent_card)
        
        # 创建应收租金总额子框架
        self.receivable_total_rent_card = self.createDashboardModule('应收租金总额', 'value')
        rent_deposit_layout.addWidget(self.receivable_total_rent_card)
        
        # 创建押金总金额子框架
        self.total_deposit_card = self.createDashboardModule('押金总金额', 'value')
        rent_deposit_layout.addWidget(self.total_deposit_card)
        
        # 将租金押金模块添加到主模块布局中
        modules_layout.addWidget(rent_deposit_group, 7)  # 减少30%宽度，使用整数比例
        
        # 创建合同到期明细模块
        contract_expiry_details_group = QGroupBox('合同到期明细')
        contract_expiry_details_layout = QVBoxLayout(contract_expiry_details_group)
        contract_expiry_details_layout.setSpacing(5)  # 设置垂直布局中的间距
        contract_expiry_details_layout.setContentsMargins(10, 10, 10, 10)
        
        # 设置标题字体 - 设置为加粗字体
        font = QFont()
        font.setPointSize(10)
        font.setBold(True)  # 设置为粗体
        font.setWeight(QFont.Bold)  # 设置为粗体字重
        contract_expiry_details_group.setFont(font)
        
        # 保存引用以便后续更新主题
        self.contract_expiry_details_group = contract_expiry_details_group
        # 设置标题文本居中对齐和标题行高度,并通过样式表强制使用粗体字体
        contract_expiry_details_group.setStyleSheet(
            "QGroupBox {font-weight: bold; text-align: center; font-family: 'Microsoft YaHei';}"
            "QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; height: 9px; font-weight: bold;}"
        )
        
        # 创建列表显示组件（使用QTreeWidget作为提醒日志的组件）
        self.contract_expiry_details_list = QTreeWidget()
        self.contract_expiry_details_list.setHeaderLabels(['序号', '到期日期', '合同编号', '房屋编号', '承租人'])
        
        # 设置列表表头字体为常规字体并水平居中
        header = self.contract_expiry_details_list.header()
        header_font = QFont()
        header_font.setPointSize(10)
        header_font.setBold(False)  # 非粗体
        header_font.setWeight(QFont.Normal)  # 常规字重
        header_font.setFamily('Microsoft YaHei')
        header.setFont(header_font)
        
        # 设置表头样式表,确保文字水平居中
        self.contract_expiry_details_list.setStyleSheet(
            "QHeaderView::section {"
            "font-weight: normal;"
            "background-color: #f5f5f5;"
            "border: 1px solid #ddd;"
            "}"
        )
        
        # 添加双击事件连接
        self.contract_expiry_details_list.itemDoubleClicked.connect(self.showContractDetails)
        
        # 为每个表头项设置水平居中对齐
        for i in range(self.contract_expiry_details_list.columnCount()):
            header_item = self.contract_expiry_details_list.headerItem()
            if header_item:
                header_item.setTextAlignment(i, Qt.AlignCenter)
        self.contract_expiry_details_list.setColumnWidth(0, 45)  # 序号列宽度
        self.contract_expiry_details_list.setColumnWidth(1, 120)  # 到期日期列宽度
        self.contract_expiry_details_list.setColumnWidth(4, 150)  # 合同编号列宽度
        self.contract_expiry_details_list.setColumnWidth(2, 90)  # 房屋编号列宽度
        self.contract_expiry_details_list.setColumnWidth(3, 120)  # 承租人列宽度
     
        self.contract_expiry_details_list.setMinimumHeight(100)  # 确保列表有足够的显示高度
        contract_expiry_details_layout.addWidget(self.contract_expiry_details_list)
        
        # 将合同到期明细模块添加到主模块布局中
        modules_layout.addWidget(contract_expiry_details_group, 13)  # 增加宽度以接收释放的空间，使用整数比例
        
        # 创建租金到期明细模块（样式与合同到期明细模块一致）
        rent_reminder_group = QGroupBox('租金到期明细')
        rent_reminder_layout = QVBoxLayout(rent_reminder_group)
        rent_reminder_layout.setSpacing(5)  # 设置垂直布局中的间距
        rent_reminder_layout.setContentsMargins(10, 10, 10, 10)
        
        # 设置标题字体 - 设置为加粗字体
        font = QFont()
        font.setPointSize(10)
        font.setBold(True)
        rent_reminder_group.setFont(font)
        
        # 保存引用以便后续更新主题
        self.rent_reminder_group = rent_reminder_group
        # 设置标题文本居中对齐和标题行高度
        rent_reminder_group.setStyleSheet("QGroupBox {font-weight: bold; text-align: center; font-family: 'Microsoft YaHei';}" "QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; height: 9px; font-weight: bold;}")
        
        # 创建列表显示组件（使用QTreeWidget）
        self.rent_reminder_list = QTreeWidget()
        self.rent_reminder_list.setHeaderLabels(['序号', '到期日期', '合同编号', '房屋编号', '承租方'])
        
        # 设置列表表头字体为常规字体并水平居中
        header = self.rent_reminder_list.header()
        header_font = QFont()
        header_font.setPointSize(10)
        header_font.setBold(False)  # 非粗体
        header_font.setWeight(QFont.Normal)  # 常规字重
        header_font.setFamily('Microsoft YaHei')
        header.setFont(header_font)
        
        # 设置表头样式表,确保文字水平居中
        self.rent_reminder_list.setStyleSheet(
            "QHeaderView::section {"
            "font-weight: normal;"
            "background-color: #f5f5f5;"
            "border: 1px solid #ddd;"
            "}"
        )
        
        # 为每个表头项设置水平居中对齐
        for i in range(self.rent_reminder_list.columnCount()):
            header_item = self.rent_reminder_list.headerItem()
            if header_item:
                header_item.setTextAlignment(i, Qt.AlignCenter)
        self.rent_reminder_list.setColumnWidth(0, 45)  # 序号列宽度
        self.rent_reminder_list.setColumnWidth(1, 120)  # 到期日期列宽度
        self.rent_reminder_list.setColumnWidth(2, 150)  # 合同编号列宽度
        self.rent_reminder_list.setColumnWidth(3, 90)  # 房屋编号列宽度
        self.rent_reminder_list.setColumnWidth(4, 120)  # 承租方列宽度
        self.rent_reminder_list.setMinimumHeight(100)  # 确保列表有足够的显示高度
        rent_reminder_layout.addWidget(self.rent_reminder_list)
        
        # 将租金到期明细模块添加到主模块布局中
        modules_layout.addWidget(rent_reminder_group, 13)  # 增加宽度以接收释放的空间，使用整数比例
        
        # 添加模块区域到主布局
        main_layout.addLayout(modules_layout, 0, 0)
        
        # 创建图表区域
        chart_layout = QVBoxLayout()
        chart_layout.setSpacing(10)
        chart_label = QLabel('租金收入趋势')
        font = QFont()
        font.setPointSize(12)
        font.setBold(True)
        chart_label.setFont(font)
        chart_layout.addWidget(chart_label)
        
        # 添加图表区域到主布局
        main_layout.addLayout(chart_layout, 1, 0)
        
        # 创建图表画布
        self.figure = Figure(figsize=(10, 5), dpi=100)
        self.canvas = FigureCanvas(self.figure)
        chart_layout.addWidget(self.canvas)
        
        # 图表区域已在上方添加到主布局
    
    def createDashboardModule(self, title, module_type):
        """
        创建仪表盘模块,统一所有模块的视觉样式
        
        参数:
            title: 模块标题
            module_type: 模块类型,'value'表示数值显示模块,'list'表示列表显示模块
        
        返回:
            统一样式的QGroupBox模块
        """
        # 创建模块容器
        module = QGroupBox(title)
        module_layout = QVBoxLayout(module)
        module_layout.setSpacing(8)
        module_layout.setContentsMargins(10, 10, 10, 10)
        
        # 设置标题字体
        font = QFont()
        font.setPointSize(10)
        font.setBold(True)
        module.setFont(font)
        
        # 根据模块类型创建不同的内容组件
        if module_type == 'value':
            # 数值显示模块
            value_label = QLabel('0')
            value_label.setObjectName('statValue')
            value_label.setAlignment(Qt.AlignCenter)
            # 通过样式表直接设置字体大小、粗细和颜色
            value_label.setStyleSheet("color: blue; font-size: 13pt; font-weight: bold;")
            # 设置大小策略,确保标签可以充分利用空间显示大字体
            value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            # 设置足够的最小高度,确保能容纳20pt字体
            value_label.setMinimumHeight(20)
            module_layout.addWidget(value_label)
        elif module_type == 'list':
            # 列表显示模块
            list_widget = QTextEdit()
            list_widget.setReadOnly(True)
            list_widget.setPlaceholderText(f'暂无{title}')
            list_widget.setMinimumHeight(20)  # 确保列表有足够的显示高度
            module_layout.addWidget(list_widget)
            
        # 设置统一的大小策略
        module.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        
        return module
    
    def updateDashboard(self, total_contracts, active_contracts, completed_contracts, overdue_contracts, receivable_rent, received_rent, annual_rent, total_deposit, contract_expiry_details=None):
        """更新仪表盘数据
        
        功能: 更新仪表盘上所有统计数据和列表内容,确保使用主题相关的颜色以符合可访问性标准
        """
        # 更新仪表盘数据
        # 更新合同情况模块数据
        self.total_contracts_count_card.findChild(QLabel, 'statValue').setText(str(total_contracts))
        self.active_contracts_count_card.findChild(QLabel, 'statValue').setText(str(active_contracts))
        self.completed_contracts_count_card.findChild(QLabel, 'statValue').setText(str(completed_contracts))
        self.overdue_contracts_count_card.findChild(QLabel, 'statValue').setText(str(overdue_contracts))
        
        # 更新租金押金模块数据（添加千分位分节格式）
        self.annual_rent_card.findChild(QLabel, 'statValue').setText(f'{annual_rent:,.0f}')
        self.received_total_rent_card.findChild(QLabel, 'statValue').setText(f'{received_rent:,.0f}')
        self.receivable_total_rent_card.findChild(QLabel, 'statValue').setText(f'{receivable_rent:,.0f}')
        self.total_deposit_card.findChild(QLabel, 'statValue').setText(f'{total_deposit:,.0f}')
        
        # 更新合同到期明细
        if contract_expiry_details is not None:
            # 清空现有内容
            self.contract_expiry_details_list.clear()
            
            # 获取主题相关的背景色
            alt_bg_color = None
            try:
                # 尝试获取主题实例
                theme = None
                parent = self.parent()
                while parent:
                    if hasattr(parent, 'theme'):
                        theme = parent.theme
                        break
                    parent = parent.parent()
                
                # 如果找到主题实例,使用主题中的替代背景色
                if theme:
                    alt_bg_color = theme.colors.get('background_alt', '#2a2a2a')
            except Exception:
                # 出错时使用默认值
                alt_bg_color = '#f0f0f0'  # 明亮主题的默认值
            
            if not contract_expiry_details:
                # 如果没有数据,添加一个提示项
                item = QTreeWidgetItem(['', '暂无合同到期明细', '', '', ''])
                self.contract_expiry_details_list.addTopLevelItem(item)
            else:
                # 填充数据到树形控件
                for i, detail in enumerate(contract_expiry_details, 1):
                    item = QTreeWidgetItem([str(i), detail['end_date'], detail['contract_no'], detail['house_no'], detail['lessee']])
                    
                    # 设置隔行背景色:偶数行使用主题中的替代背景色
                    if i % 2 == 0 and alt_bg_color:
                        for j in range(5):
                            item.setBackground(j, QBrush(QColor(alt_bg_color)))
                    
                    self.contract_expiry_details_list.addTopLevelItem(item)
                
                # 自动调整列宽以适应内容
                for column in range(self.contract_expiry_details_list.columnCount()):
                    self.contract_expiry_details_list.resizeColumnToContents(column)
            
            # 应用主题样式到新添加的项目
            self.applyThemeStyle()
    
    def applyThemeStyle(self):
        """
        应用当前主题样式到仪表盘组件
        
        功能: 根据当前应用的主题,动态设置列表标题、表头和列表项的样式,确保在深色主题下正确显示
        特别注意: 确保所有文本与背景的对比度符合WCAG AA级标准(正常文本对比度≥4.5:1,大文本≥3:1)
        """
        try:
            # 导入必要模块
            from modern_theme import ModernTheme
            from PyQt5.QtGui import QBrush, QColor
            
            # 获取当前应用的主题实例
            theme = None
            # 通过父窗口查找MainWindow实例
            parent = self.parent()
            while parent:
                if hasattr(parent, 'theme'):
                    theme = parent.theme
                    break
                parent = parent.parent()
            
            # 如果没有找到主题实例,创建默认主题
            if theme is None:
                theme = ModernTheme()
            
            # 获取当前主题的颜色
            bg_color = theme.colors['background']
            bg_alt_color = theme.colors['background_alt']
            secondary_color = theme.colors['secondary']
            text_color = theme.colors['text']
            text_light_color = theme.colors['text_light']
            border_color = theme.colors['border']
            
            # 为合同到期明细列表标题应用主题样式
            if hasattr(self, 'contract_expiry_details_group'):
                self.contract_expiry_details_group.setStyleSheet(
                    f"QGroupBox {{background-color: {bg_color}; color: {text_color}; font-weight: bold; text-align: center; font-family: 'Microsoft YaHei'; border: 1px solid {border_color};}}"
                    f"QGroupBox::title {{subcontrol-origin: margin; left: 7px; padding: 0 3px 0 3px; height: 9px; font-weight: bold; color: {text_color};}}"
                )
            
            # 为租金到期明细列表标题应用主题样式
            if hasattr(self, 'rent_reminder_group'):
                self.rent_reminder_group.setStyleSheet(
                    f"QGroupBox {{background-color: {bg_color}; color: {text_color}; font-weight: bold; text-align: center; font-family: 'Microsoft YaHei'; border: 1px solid {border_color};}}"
                    f"QGroupBox::title {{subcontrol-origin: margin; left: 7px; padding: 0 3px 0 3px; height: 9px; font-weight: bold; color: {text_color};}}"
                )
            
            # 为合同到期明细列表表头和主体应用主题样式
            if hasattr(self, 'contract_expiry_details_list'):
                # 设置列表整体样式
                self.contract_expiry_details_list.setStyleSheet(
                    f"QTreeWidget {{background-color: {bg_color}; color: {text_color}; border: 1px solid {border_color};}} "
                    f"QHeaderView::section "
                    f"{{"
                    f"font-weight: normal;"
                    f"background-color: {secondary_color};"
                    f"color: {text_color};"
                    f"border: 1px solid {border_color};"
                    f"padding: 5px;"
                    f"}}"
                )
                
                # 更新现有列表项的样式
                for i in range(self.contract_expiry_details_list.topLevelItemCount()):
                    item = self.contract_expiry_details_list.topLevelItem(i)
                    # 设置隔行背景色
                    if i % 2 == 1:
                        for j in range(item.columnCount()):
                            item.setBackground(j, QBrush(QColor(bg_alt_color)))
                    # 确保文本颜色符合对比度标准
                    for j in range(item.columnCount()):
                        item.setForeground(j, QBrush(QColor(text_color)))
            
            # 为租金到期明细列表表头和主体应用主题样式
            if hasattr(self, 'rent_reminder_list'):
                # 设置列表整体样式
                self.rent_reminder_list.setStyleSheet(
                    f"QTreeWidget {{background-color: {bg_color}; color: {text_color}; border: 1px solid {border_color};}} "
                    f"QHeaderView::section "
                    f"{{"
                    f"font-weight: normal;"
                    f"background-color: {secondary_color};"
                    f"color: {text_color};"
                    f"border: 1px solid {border_color};"
                    f"padding: 5px;"
                    f"}}"
                )
                
                # 更新现有列表项的样式
                for i in range(self.rent_reminder_list.topLevelItemCount()):
                    item = self.rent_reminder_list.topLevelItem(i)
                    # 设置隔行背景色
                    if i % 2 == 1:
                        for j in range(item.columnCount()):
                            item.setBackground(j, QBrush(QColor(bg_alt_color)))
                    # 确保文本颜色符合对比度标准
                    for j in range(item.columnCount()):
                        item.setForeground(j, QBrush(QColor(text_color)))
            
            # 处理仪表盘上的标签文本颜色
            if hasattr(self, 'total_contracts_value'):
                self.total_contracts_value.setStyleSheet(f"color: {text_color}; font-size: 20pt; font-weight: bold;")
            if hasattr(self, 'active_contracts_value'):
                self.active_contracts_value.setStyleSheet(f"color: {text_color}; font-size: 20pt; font-weight: bold;")
            if hasattr(self, 'expired_contracts_value'):
                self.expired_contracts_value.setStyleSheet(f"color: {text_color}; font-size: 20pt; font-weight: bold;")
            if hasattr(self, 'total_rent_value'):
                self.total_rent_value.setStyleSheet(f"color: {text_color}; font-size: 20pt; font-weight: bold;")
                
        except Exception as e:
            # 出错时记录日志但不影响程序运行
            from logger_module import log_error
            log_error(f"应用主题样式到仪表盘时出错: {str(e)}")
    
    def updateReminders(self, rent_reminders):
        """更新租金到期提醒
        
        功能: 将租金到期提醒数据显示在相应的树形控件中,统一格式并按日期排序,设置隔行背景色
        确保所有文本与背景的对比度符合WCAG AA级标准
        
        参数:
            rent_reminders: 租金到期提醒列表
        """
        # 更新租金到期提醒
        if rent_reminders is not None:
            # 清空现有内容
            self.rent_reminder_list.clear()
            
            # 获取主题相关的背景色
            alt_bg_color = None
            try:
                # 尝试获取主题实例
                theme = None
                parent = self.parent()
                while parent:
                    if hasattr(parent, 'theme'):
                        theme = parent.theme
                        break
                    parent = parent.parent()
                
                # 如果找到主题实例,使用主题中的替代背景色
                if theme:
                    alt_bg_color = theme.colors.get('background_alt', '#2a2a2a')
            except Exception:
                # 出错时使用默认值
                alt_bg_color = '#f0f0f0'  # 明亮主题的默认值
            
            if not rent_reminders:
                # 如果没有数据,添加一个提示项
                item = QTreeWidgetItem(['', '暂无租金到期提醒', '', '', ''])
                self.rent_reminder_list.addTopLevelItem(item)
            else:
                # 按到期日期排序（升序）
                sorted_rent_reminders = sorted(rent_reminders, key=lambda x: x['due_date'])
                # 填充数据到树形控件
                for i, reminder in enumerate(sorted_rent_reminders, 1):
                    # 获取房屋编号（从合同信息中提取或使用默认值）
                    house_no = reminder.get('house_no', '未知')
                    # 获取承租方
                    lessee = reminder.get('lessee', '未知')
                    item = QTreeWidgetItem([str(i), reminder['due_date'], reminder['contract_no'], house_no, lessee])
                    
                    # 设置隔行背景色:偶数行使用主题中的替代背景色
                    if i % 2 == 0 and alt_bg_color:
                        for j in range(5):
                            item.setBackground(j, QBrush(QColor(alt_bg_color)))
                    
                    self.rent_reminder_list.addTopLevelItem(item)
                
                # 自动调整列宽以适应内容
                for column in range(self.rent_reminder_list.columnCount()):
                    self.rent_reminder_list.resizeColumnToContents(column)
            
            # 应用主题样式到新添加的项目
            self.applyThemeStyle()
    
    def showContractDetails(self, item, column):
        """
        显示合同详细信息
        
        功能: 当用户在合同到期明细列表中双击记录时,显示对应的合同详细信息
        
        参数:
            item: 被双击的列表项
            column: 被双击的列
        """
        # 导入auth_manager用于记录操作日志
        from user_auth import auth_manager
        
        # 检查是否是提示项
        if item.text(1) == '暂无合同到期明细':
            return
        
        # 获取合同编号
        contract_no = item.text(2)
        if not contract_no:
            return
        
        try:
            # 记录查看合同详情操作
            record_operation(
                auth_manager.current_user_id,
                auth_manager.current_user,
                '合同管理',
                '查看合同详情',
                '成功',
                f'查看合同编号: {contract_no} 的详细信息'
            )
            
            # 连接数据库并获取合同详细信息
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                QMessageBox.warning(self, '错误', '无法连接到数据库,请检查数据库设置!')
                return
            
            try:
                cursor = conn.cursor()
                cursor.execute("SELECT * FROM contracts WHERE contract_no = ?", (contract_no,))
                contract = cursor.fetchone()
                
                if not contract:
                    # 记录查询的合同编号到日志
                    from logger_module import log_info
                    log_info(f"尝试查询合同编号: {contract_no}, 但未找到记录")
                    # 检查表是否存在
                    cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='contracts'")
                    if not cursor.fetchone():
                        QMessageBox.warning(self, '错误', '数据库中不存在contracts表!')
                    else:
                        # 显示部分合同列表以便调试
                        cursor.execute("SELECT contract_no FROM contracts LIMIT 5")
                        existing_contracts = cursor.fetchall()
                        log_info(f"数据库中存在的部分合同编号: {existing_contracts}")
                        QMessageBox.warning(self, '警告', f'找不到合同编号为【{contract_no}】的详细信息!')
                    return
            except Exception as e:
                from logger_module import log_error
                log_error(f"查询合同详情时出错: {str(e)}")
                QMessageBox.warning(self, '错误', f'查询合同时出错: {str(e)}')
                return
            
            # 获取列名
            column_names = [desc[0] for desc in cursor.description]
            
            # 创建英文字段名到中文名称的映射
            column_name_map = {
                'id': 'ID',
                'contract_no': '合同编号',
                'sign_date': '签约日期',
                'sign_year_month': '签约年月',
                'house_no': '房屋编号',
                'house_location': '房屋位置',
                'house_area': '房屋面积',
                'lessor': '出租人',
                'legal_representative': '法定代表人',
                'person_in_charge': '负责人',
                'contact_phone': '联系电话',
                'lessee': '承租人',
                'tenant': '租户',
                'tenant_id': '租户身份证',
                'tenant_phone': '租户电话',
                'start_date': '起租日期',
                'end_date': '到期日期',
                'status': '状态',
                'payment_method': '付款方式',
                'monthly_rent': '月租金',
                'total_rent': '总租金',
                'annual_rent': '年租金',
                'deposit': '押金',
                'usage': '用途',
                'utility_method': '水电费结算方式',
                'water_fee': '水费',
                'electricity_fee': '电费',
                'remarks': '备注'
            }
            
            # 将字段映射到数据字典中,便于按类别访问
            contract_dict = {col_name: contract[i] for i, col_name in enumerate(column_names)}
            
            # 创建详情窗口
            detail_window = QDialog()
            detail_window.setWindowTitle(f'合同详情 - {contract_no}')
            # 设置窗口高度为400
            detail_window.resize(800, 400)
            
            # 创建主布局
            main_layout = QVBoxLayout(detail_window)
            
            # 创建内容区域的滚动区域
            scroll_area = QScrollArea()
            scroll_area.setWidgetResizable(True)
            content_widget = QWidget()
            content_layout = QVBoxLayout(content_widget)
            content_layout.setSpacing(10)  # 设置组件间距
            
            # 设置字体
            default_font = QFont()
            default_font.setFamily('Microsoft YaHei')
            default_font.setPointSize(10)
            
            # 1. 基本信息组（两列布局）
            basic_info_group = QGroupBox('基本信息')
            basic_info_group.setFont(default_font)
            basic_info_layout = QGridLayout(basic_info_group)
            basic_info_layout.setSpacing(10)  # 设置网格间距
            basic_info_layout.setContentsMargins(10, 10, 10, 10)
            
            # 添加基本信息字段（分成两列）
            basic_info_fields = [
                ('contract_no', '合同编号'),
                ('sign_date', '签约日期'),
                ('sign_year_month', '签约年月'),
                ('status', '状态')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(basic_info_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(basic_info_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                # 创建标签
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                # 创建值显示
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色  # 允许选择文本
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                basic_info_layout.addWidget(label_widget, row, col_offset)
                basic_info_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            basic_info_layout.setColumnMinimumWidth(0, 90)
            basic_info_layout.setColumnMinimumWidth(2, 90)
            
            # 2. 房屋信息组（两列布局）
            house_info_group = QGroupBox('房屋信息')
            house_info_group.setFont(default_font)
            house_info_layout = QGridLayout(house_info_group)
            house_info_layout.setSpacing(10)
            house_info_layout.setContentsMargins(10, 10, 10, 10)
            
            house_info_fields = [
                ('house_no', '房屋编号'),
                ('house_location', '房屋位置'),
                ('house_area', '房屋面积')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(house_info_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(house_info_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                house_info_layout.addWidget(label_widget, row, col_offset)
                house_info_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            house_info_layout.setColumnMinimumWidth(0, 90)
            house_info_layout.setColumnMinimumWidth(2, 90)
            
            # 3. 出租人信息组（两列布局）
            lessor_info_group = QGroupBox('出租人信息')
            lessor_info_group.setFont(default_font)
            lessor_info_layout = QGridLayout(lessor_info_group)
            lessor_info_layout.setSpacing(10)
            lessor_info_layout.setContentsMargins(10, 10, 10, 10)
            
            lessor_info_fields = [
                ('lessor', '出租人'),
                ('legal_representative', '法定代表人'),
                ('person_in_charge', '负责人'),
                ('contact_phone', '联系电话')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(lessor_info_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(lessor_info_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                lessor_info_layout.addWidget(label_widget, row, col_offset)
                lessor_info_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            lessor_info_layout.setColumnMinimumWidth(0, 90)
            lessor_info_layout.setColumnMinimumWidth(2, 90)
            
            # 4. 承租人信息组（两列布局）
            lessee_info_group = QGroupBox('承租人信息')
            lessee_info_group.setFont(default_font)
            lessee_info_layout = QGridLayout(lessee_info_group)
            lessee_info_layout.setSpacing(10)
            lessee_info_layout.setContentsMargins(10, 10, 10, 10)
            
            lessee_info_fields = [
                ('lessee', '承租人'),
                ('tenant', '租户'),
                ('tenant_id', '租户身份证'),
                ('tenant_phone', '租户电话')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(lessee_info_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(lessee_info_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                lessee_info_layout.addWidget(label_widget, row, col_offset)
                lessee_info_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            lessee_info_layout.setColumnMinimumWidth(0, 90)
            lessee_info_layout.setColumnMinimumWidth(2, 90)
            
            # 5. 合同期限组（两列布局）
            term_group = QGroupBox('合同期限')
            term_group.setFont(default_font)
            term_layout = QGridLayout(term_group)
            term_layout.setSpacing(10)
            term_layout.setContentsMargins(10, 10, 10, 10)
            
            term_fields = [
                ('start_date', '起租日期'),
                ('end_date', '到期日期')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(term_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(term_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                term_layout.addWidget(label_widget, row, col_offset)
                term_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            term_layout.setColumnMinimumWidth(0, 90)
            term_layout.setColumnMinimumWidth(2, 90)
            
            # 6. 租金与费用组（两列布局）
            rent_group = QGroupBox('租金与费用')
            rent_group.setFont(default_font)
            rent_layout = QGridLayout(rent_group)
            rent_layout.setSpacing(10)
            rent_layout.setContentsMargins(10, 10, 10, 10)
            
            rent_fields = [
                ('monthly_rent', '月租金'),
                ('annual_rent', '年租金'),
                ('total_rent', '总租金'),
                ('deposit', '押金'),
                ('payment_method', '付款方式')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(rent_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(rent_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                rent_layout.addWidget(label_widget, row, col_offset)
                rent_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            rent_layout.setColumnMinimumWidth(0, 90)
            rent_layout.setColumnMinimumWidth(2, 90)
            
            # 7. 其他条款组（两列布局）
            other_group = QGroupBox('其他条款')
            other_group.setFont(default_font)
            # 移除固定最小高度,改为与基本信息组一致的高度
            other_layout = QGridLayout(other_group)
            other_layout.setSpacing(10)
            other_layout.setContentsMargins(10, 10, 10, 10)
            
            other_fields = [
                ('usage', '用途'),
                ('utility_method', '水电费结算方式'),
                ('water_fee', '水费'),
                ('electricity_fee', '电费')
            ]
            
            # 计算需要多少行来容纳两列布局
            num_fields = len(other_fields)
            num_rows = (num_fields + 1) // 2  # 向上取整
            
            for i, (field, label) in enumerate(other_fields):
                # 计算行列位置（左侧列:0和1；右侧列:2和3）
                row = i % num_rows
                col_offset = 0 if i < num_rows else 2  # 左侧或右侧
                
                label_widget = QLabel(label + ':')
                label_widget.setFont(default_font)
                label_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                value = contract_dict.get(field, '')
                value_widget = QLabel(str(value) if value is not None else '')
                value_widget.setFont(default_font)
                value_widget.setTextInteractionFlags(Qt.TextSelectableByMouse)
                value_widget.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
                
                other_layout.addWidget(label_widget, row, col_offset)
                other_layout.addWidget(value_widget, row, col_offset + 1)
            
            # 设置列宽度
            other_layout.setColumnMinimumWidth(0, 90)
            other_layout.setColumnMinimumWidth(2, 90)
            
            # 8. 备注信息（特殊处理,使用多行文本框）
            remarks_group = QGroupBox('备注信息')
            remarks_group.setFont(default_font)
            remarks_layout = QVBoxLayout(remarks_group)
            remarks_layout.setContentsMargins(10, 10, 10, 10)
            
            remarks_value = contract_dict.get('remarks', '')
            remarks_textedit = QTextEdit(str(remarks_value) if remarks_value is not None else '')
            remarks_textedit.setFont(default_font)
            remarks_textedit.setReadOnly(True)
            remarks_textedit.setStyleSheet("color: blue;")  # 设置文字颜色为蓝色
            # 移除固定最小高度,改为自适应高度
            remarks_layout.addWidget(remarks_textedit)
            
            # 创建四行两列的网格布局
            grid_layout = QGridLayout()
            grid_layout.setSpacing(10)  # 设置组件间距
            
            # 计算基本信息组的理想高度
            basic_info_group.adjustSize()
            target_height = basic_info_group.sizeHint().height()
            
            # 设置其他条款和备注信息组的高度与基本信息组一致
            basic_info_group.setFixedHeight(target_height)
            other_group.setFixedHeight(target_height)
            remarks_group.setFixedHeight(target_height)
            
            # 添加所有分组到网格布局中（四行两列）
            grid_layout.addWidget(basic_info_group, 0, 0)
            grid_layout.addWidget(house_info_group, 0, 1)
            grid_layout.addWidget(lessor_info_group, 1, 0)
            grid_layout.addWidget(lessee_info_group, 1, 1)
            grid_layout.addWidget(term_group, 2, 0)
            grid_layout.addWidget(rent_group, 2, 1)
            grid_layout.addWidget(other_group, 3, 0)
            grid_layout.addWidget(remarks_group, 3, 1)
            
            # 将网格布局添加到内容布局中
            content_layout.addLayout(grid_layout)
            
            # 添加占位符,确保最后一个组件和按钮之间有间距
            content_layout.addStretch(1)
            
            # 将内容控件添加到滚动区域
            scroll_area.setWidget(content_widget)
            
            # 添加关闭按钮
            button_layout = QHBoxLayout()
            close_button = QPushButton('关闭')
            close_button.setFont(default_font)
            close_button.clicked.connect(detail_window.accept)
            button_layout.addStretch(1)
            button_layout.addWidget(close_button)
            
            # 添加到主布局
            main_layout.addWidget(scroll_area)
            main_layout.addLayout(button_layout)
            
            # 计算内容区域的理想大小
            content_widget.adjustSize()
            
            # 设置最小窗口大小,确保即使内容很少也能正常显示
            min_width = 600
            min_height = 400
            
            # 设置最大窗口尺寸,避免超出屏幕
            screen = QApplication.primaryScreen()
            screen_rect = screen.availableGeometry()
            max_width = int(screen_rect.width() * 0.8)  # 最大宽度为屏幕的80%
            max_height = int(screen_rect.height() * 0.8)  # 最大高度为屏幕的80%
            
            # 根据内容计算合适的窗口大小
            # 考虑滚动区域、按钮区域和窗口边框
            content_width = content_widget.width() + 40  # 添加一些边距
            content_height = content_widget.height() + 80  # 添加按钮和边框的高度
            
            # 确保窗口大小在最小和最大之间
            final_width = max(min_width, min(content_width, max_width))
            final_height = max(min_height, min(content_height, max_height))
            
            # 设置最终窗口大小
            detail_window.resize(final_width, final_height)
            
            # 显示窗口
            detail_window.exec_()
            
        except sqlite3.Error as e:
            # 记录失败操作
            record_operation(
                auth_manager.current_user_id,
                auth_manager.current_user,
                '合同管理',
                '查看合同详情',
                '失败',
                f'查看合同编号: {contract_no} 失败,错误: {str(e)}'
            )
            QMessageBox.warning(self, '查询失败', f'获取合同信息时出错!\n错误信息: {str(e)}')
        finally:
            if 'cursor' in locals() and cursor:
                cursor.close()
            if 'conn' in locals() and conn:
                DatabaseUtils.close_connection(conn)
    
    def updateRentTrend(self, months, receivable, received):
        """更新租金收入趋势图表 - 优化版，确保符合WCAG AA级对比度标准"""
        # 获取当前主题颜色
        is_dark_theme = self._is_dark_theme()
        
        # 根据主题设置颜色
        if is_dark_theme:
            # 深色主题颜色 - 确保符合WCAG AA级对比度
            figure_bg = '#1a1a1a'       # 图表背景
            axes_bg = '#2d2d2d'         # 绘图区域背景
            text_color = '#ffffff'      # 主文本色（白色）
            title_color = '#ffffff'     # 标题颜色
            axis_color = '#d0d0d0'      # 坐标轴和标签颜色
            grid_color = '#404040'      # 网格线颜色
            receivable_color = '#5DADE2'  # 应收柱状图颜色（亮蓝色）
            received_color = '#52BE80'    # 已收柱状图颜色（亮绿色）
            low_rate_color = '#F5B7B1'    # 低收款率颜色（亮红色）
            high_rate_color = '#52BE80'   # 高收款率颜色（亮绿色）
            legend_bg = '#3a3a3a'        # 图例背景色
            legend_text = '#ffffff'      # 图例文本色
        else:
            # 明亮主题颜色
            figure_bg = '#ffffff'       # 图表背景
            axes_bg = '#ffffff'         # 绘图区域背景
            text_color = '#333333'      # 主文本色
            title_color = '#333333'     # 标题颜色
            axis_color = '#666666'      # 坐标轴和标签颜色
            grid_color = '#e0e0e0'      # 网格线颜色
            receivable_color = '#2c3e50'  # 应收柱状图颜色（深灰色）
            received_color = '#27ae60'    # 已收柱状图颜色（绿色）
            low_rate_color = '#e74c3c'    # 低收款率颜色（红色）
            high_rate_color = '#27ae60'   # 高收款率颜色（绿色）
            legend_bg = '#ffffff'        # 图例背景色
            legend_text = '#333333'      # 图例文本色
        
        # 设置图表背景色
        self.figure.patch.set_facecolor(figure_bg)
        self.figure.clear()
        
        ax = self.figure.add_subplot(111)
        
        # 设置轴背景色
        ax.set_facecolor(axes_bg)
        
        # 设置文本颜色
        for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
                     ax.get_xticklabels() + ax.get_yticklabels()):
            item.set_color(axis_color)
        
        # 优化柱状图宽度和间距
        width = 0.3
        x = range(len(months))
        
        # 绘制应收金额柱状图
        bars1 = ax.bar([i - width/2 for i in x], receivable, width, 
                      label='应收租金', color=receivable_color, edgecolor=axis_color, linewidth=1)
        # 绘制已收金额柱状图
        bars2 = ax.bar([i + width/2 for i in x], received, width, 
                      label='实际收款', color=received_color, edgecolor=axis_color, linewidth=1)
        
        # 添加网格线便于数值对比
        ax.grid(axis='y', linestyle='--', alpha=0.7, color=grid_color)
        
        # 计算收款率并添加标签
        max_height = 0
        for i in range(len(months)):
            # 应收标签
            if receivable[i] > 0:
                ax.annotate(f'{receivable[i]:.2f}',
                            xy=(i - width/2, receivable[i]),
                            xytext=(0, 5),
                            textcoords="offset points",
                            ha='center', va='bottom', fontsize=8, color=text_color)
                
            # 已收标签
            if received[i] > 0:
                ax.annotate(f'{received[i]:.2f}',
                            xy=(i + width/2, received[i]),
                            xytext=(0, 5),
                            textcoords="offset points",
                            ha='center', va='bottom', fontsize=8, color=text_color)
                
            # 计算收款率并显示
            if receivable[i] > 0:
                rate = (received[i] / receivable[i]) * 100
                # 在两柱之间显示收款率
                rate_color = low_rate_color if rate < 80 else high_rate_color
                ax.annotate(f'{rate:.1f}%',
                            xy=(i, max(receivable[i], received[i])),
                            xytext=(0, 15),
                            textcoords="offset points",
                            ha='center', va='bottom', fontsize=8, color=rate_color)
            
            # 跟踪最大高度以调整图表范围
            max_height = max(max_height, receivable[i], received[i])
        
        # 设置坐标轴和标题
        ax.set_xlabel('月份', fontsize=8, color=text_color)
        ax.set_ylabel('金额（元）', fontsize=8, color=text_color)
        ax.set_title('最近12个月租金应收实收趋势对比', fontsize=10, fontweight='bold',pad=20, color=title_color)
        
        # 设置x轴刻度,优化月份标签显示
        ax.set_xticks(x)
        ax.set_xticklabels(months, rotation=45, ha='right', fontsize=8, color=text_color)
        
        # 优化图例
        legend = ax.legend(loc='upper left', fontsize=8, frameon=True, shadow=True)
        legend.get_frame().set_facecolor(legend_bg)
        for text in legend.get_texts():
            text.set_color(legend_text)
        
        # 调整y轴范围,为标签留出空间
        if max_height > 0:
            ax.set_ylim(0, max_height * 1.25)
        
        # 优化整体布局
        self.figure.tight_layout()
        self.figure.subplots_adjust(top=0.88, bottom=0.2)
        
        self.canvas.draw()
        
    def _is_dark_theme(self):
        """检测当前是否使用深色主题
        
        返回:
            bool: True表示深色主题，False表示明亮主题
        """
        try:
            # 尝试获取主题实例
            parent = self.parent()
            while parent:
                if hasattr(parent, 'theme'):
                    return parent.theme.name == 'dark'
                parent = parent.parent()
        except Exception:
            pass
        return False

# 合同管理标签页
class ContractTab(QWidget):
    # 定义数据更新信号
    data_updated = pyqtSignal()
    # 添加用于异步加载的信号
    data_loaded = pyqtSignal(list, object)
    loading_started = pyqtSignal()
    loading_finished = pyqtSignal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent  # 保存父窗口引用
        # 导入auth_manager以在整个类中使用
        from user_auth import auth_manager
        self.auth_manager = auth_manager
        # 初始化线程池
        self.thread_pool = QThreadPool()
        self.thread_pool.setMaxThreadCount(2)  # 限制线程数
        # 连接异步信号
        self.data_loaded.connect(self.onDataLoaded)
        self.loading_started.connect(self.onLoadingStarted)
        self.loading_finished.connect(self.onLoadingFinished)
        self.initUI()
    
    def initUI(self):
        # 创建主布局 - 使用QGridLayout以支持加载指示器
        main_layout = QGridLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        
        # 创建搜索和操作按钮区域
        search_layout = QHBoxLayout()
        
        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText('搜索所有非数字字段（合同编号、承租方、承租人、房屋位置等）')
        search_layout.addWidget(self.search_input)
        
        # 搜索按钮
        search_button = QPushButton('搜索')
        search_button.clicked.connect(self.searchContracts)
        search_layout.addWidget(search_button)
        
        # 重置按钮
        reset_button = QPushButton('重置')
        reset_button.clicked.connect(self.resetSearch)
        search_layout.addWidget(reset_button)
        
        # 绑定回车事件
        self.search_input.returnPressed.connect(self.searchContracts)
        
        # 添加合同按钮
        add_button = QPushButton('添加合同')
        add_button.clicked.connect(self.addContract)
        search_layout.addWidget(add_button)
        
        # 编辑合同按钮
        self.edit_button = QPushButton('编辑合同')
        self.edit_button.clicked.connect(self.editContract)
        self.edit_button.setEnabled(False)
        search_layout.addWidget(self.edit_button)
        
        # 删除合同按钮
        self.delete_button = QPushButton('删除合同')
        self.delete_button.clicked.connect(self.deleteContract)
        self.delete_button.setEnabled(False)
        search_layout.addWidget(self.delete_button)
        
        # 收款明细按钮
        self.payment_details_button = QPushButton('收款明细')
        self.payment_details_button.clicked.connect(self.showPaymentDetails)
        self.payment_details_button.setEnabled(False)
        search_layout.addWidget(self.payment_details_button)
        
        # 导出按钮
        export_button = QPushButton('导出数据')
        export_button.clicked.connect(self.exportContracts)
        search_layout.addWidget(export_button)
        
        # 导入Excel按钮
        import_excel_button = QPushButton('导入Excel')
        import_excel_button.clicked.connect(self.importContractsFromExcel)
        search_layout.addWidget(import_excel_button)
        
        # 添加搜索和操作按钮区域到主布局 - 已在下方添加，这里移除重复调用
        
        # 创建合同表格
        self.contract_table = QTableWidget()
        self.contract_table.setColumnCount(18)  # 显示部分重要字段（新增季度租金列,以及已收总租金、应收总租金、收款情况列）
        self.contract_table.setHorizontalHeaderLabels(['合同编号', '签约日期', '房屋编号', '房屋类型', '房屋位置', '承租方', '承租人', '租赁开始日期', '租赁截止日期', '合同状态', '租金支付方式', '月租金额', '季度租金', '年租金总额', '押金金额', '已收总租金', '应收总租金', '收款情况'])
        
        # 设置表格属性
        # 初始时为所有列设置固定宽度作为默认值，在数据加载完成后再调整为自适应
        # 为不同类型的列设置合理的初始宽度
        column_widths = [
            150,  # 合同编号
            120,  # 签约日期
            100,  # 房屋编号
            80,   # 房屋类型
            150,  # 房屋位置
            150,  # 承租方
            100,  # 承租人
            120,  # 租赁开始日期
            120,  # 租赁截止日期
            80,   # 合同状态
            100,  # 租金支付方式
            100,  # 月租金额
            100,  # 季度租金
            100,  # 年租金总额
            100,  # 押金金额
            100,  # 已收总租金
            100,  # 应收总租金
            80    # 收款情况
        ]
        
        # 初始设置所有列为固定宽度
        for col in range(self.contract_table.columnCount()):
            self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Fixed)
            if col < len(column_widths):
                self.contract_table.setColumnWidth(col, column_widths[col])
        
        # 自定义'租金支付方式'列标题为两行显示并设置字体大小
        payment_method_col = 10  # 租金支付方式列的索引
        
        # 创建自定义表头项
        header_item = QTableWidgetItem('租金\n支付方式')
        header_item.setTextAlignment(Qt.AlignCenter)  # 设置文本居中对齐
        
        # 设置表头项字体为9号
        font = header_item.font()
        font.setPointSize(9)
        header_item.setFont(font)
        
        # 设置表头项
        self.contract_table.setHorizontalHeaderItem(payment_method_col, header_item)
        
        # 增加表头高度以容纳两行文本
        header = self.contract_table.horizontalHeader()
        current_height = header.height()
        header.setMinimumHeight(max(current_height, 40))  # 确保有足够高度显示两行
        
        # 保存支付方式列的索引，以便在窗口调整大小时保持其样式
        self.payment_method_col = payment_method_col
        
        # 为所有列标题设置字体大小（比默认小1个单位）
        header_font = QFont()
        header_font.setPointSize(9)  # 设置为9号字体
        for col in range(self.contract_table.columnCount()):
            header_item = self.contract_table.horizontalHeaderItem(col)
            if header_item:
                header_item.setFont(header_font)
                
        # 性能优化设置
        self.contract_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.contract_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 优化表格性能设置
        self.contract_table.setAlternatingRowColors(True)  # 启用交替行颜色以提高可读性
        self.contract_table.setVerticalScrollMode(QTableWidget.ScrollPerItem)  # 按项滚动更高效
        self.contract_table.setAutoScroll(False)  # 禁用自动滚动
        self.contract_table.setUpdatesEnabled(True)  # 启用更新
        
        # 优化性能
        self.contract_table.setSortingEnabled(False)  # 默认禁用排序，数据加载完成后再启用
        self.contract_table.setSelectionMode(QTableWidget.SingleSelection)  # 单选模式提高性能
        self.contract_table.horizontalHeader().setHighlightSections(False)  # 禁用表头高亮，减少绘制
        
        # 创建统计信息区域
        stats_layout = QHBoxLayout()
        stats_layout.setSpacing(15)
        stats_layout.setContentsMargins(10, 5, 10, 5)
        
        # 创建统计标签
        self.total_contracts_label = QLabel('合同总数: 0')
        self.active_contracts_label = QLabel('执行中合同: 0')
        self.completed_contracts_label = QLabel('已完成合同: 0')
        self.overdue_contracts_label = QLabel('逾期合同: 0')
        
        # 设置标签样式
        font = QFont()
        font.setPointSize(10)
        for label in [self.total_contracts_label, self.active_contracts_label, 
                     self.completed_contracts_label, self.overdue_contracts_label]:
            label.setFont(font)
            label.setStyleSheet('color: #333;')
        
        # 添加到统计布局
        stats_layout.addWidget(self.total_contracts_label)
        stats_layout.addWidget(self.active_contracts_label)
        stats_layout.addWidget(self.completed_contracts_label)
        stats_layout.addWidget(self.overdue_contracts_label)
        stats_layout.addStretch(1)
        
        # 创建表格区域容器
        table_container = QWidget()
        table_container_layout = QVBoxLayout(table_container)
        table_container_layout.setContentsMargins(0, 0, 0, 0)
        table_container_layout.setSpacing(0)
        table_container_layout.addWidget(self.contract_table)  # 直接添加表格，不使用额外的滚动区域
        table_container_layout.addLayout(stats_layout)
        
        # 创建加载指示器
        self.loading_indicator = QLabel()
        self.loading_indicator.setText('加载中...')
        self.loading_indicator.setAlignment(Qt.AlignCenter)
        self.loading_indicator.setStyleSheet('font-size: 14px; color: #666;')
        self.loading_indicator.hide()
        
        # 添加到主布局
        main_layout.addLayout(search_layout, 0, 0)
        main_layout.addWidget(table_container, 1, 0)
        main_layout.addWidget(self.loading_indicator, 1, 0, Qt.AlignCenter)
        
        # 初始化数据存储
        self.all_contract_data = []  # 存储所有数据
        
        # 异步加载合同数据
        self.loadContracts()
        
        # 设置表格的滚动条策略
        self.contract_table.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.contract_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        
        # 连接单元格点击信号
        self.contract_table.cellClicked.connect(self.onCellClicked)
        # 添加双击打开编辑窗口功能
        self.contract_table.cellDoubleClicked.connect(self.editContract)
        
        # 创建统计信息区域
        stats_layout = QHBoxLayout()
        stats_layout.setContentsMargins(10, 10, 10, 10)
        stats_layout.setSpacing(20)
        
        # 创建统计标签
        self.total_count_label = QLabel('合计笔数: 0')
        self.settled_count_label = QLabel('已结清笔数: 0')
        self.unsettled_count_label = QLabel('未结清笔数: 0')
        self.monthly_total_label = QLabel('月总租金: ¥0.00')
        self.quarterly_total_label = QLabel('季总租金: ¥0.00')
        self.annual_total_label = QLabel('年总租金: ¥0.00')
        self.deposit_total_label = QLabel('押金总金额: ¥0.00')
        # 新增统计标签
        self.received_total_label = QLabel('已收总租金: ¥0.00')
        self.receivable_total_label = QLabel('应收总租金: ¥0.00')
        
        # 设置标签样式
        font = QFont()
        font.setPointSize(11)
        font.setBold(False)
        
        for label in [self.total_count_label, self.settled_count_label, self.unsettled_count_label, 
                     self.monthly_total_label, self.quarterly_total_label, self.annual_total_label, 
                     self.deposit_total_label, self.received_total_label, self.receivable_total_label]:
            label.setFont(font)
            stats_layout.addWidget(label)
        
        # 将统计信息区域添加到主布局
        main_layout.addLayout(stats_layout, 2, 0)
        
        # 设置行和列的拉伸因子
        main_layout.setRowStretch(1, 1)  # 表格区域可拉伸
    

    
    def loadContracts(self, conn=None):
        """异步加载合同数据到表格 - 高性能优化版"""
        # 发射加载开始信号
        self.loading_started.emit()
        
        # 获取数据库连接路径
        from db_utils import DatabaseUtils
        db_path = DatabaseUtils.get_db_path()
        
        # 创建工作线程
        worker = DataLoaderWorker(
            func=None,
            db_path=db_path,
            query_type='load_contracts',
            search_text=None
        )
        
        # 连接工作线程信号
        worker.signals.list_result.connect(self.onDataLoaded)
        worker.signals.error.connect(self.handleWorkerError)
        worker.signals.finished.connect(self.loading_finished)
        
        # 启动线程
        self.thread_pool.start(worker)
    
    def searchContracts(self):
        """异步搜索合同数据"""
        search_text = self.search_input.text().strip()
        
        # 发射加载开始信号
        self.loading_started.emit()
        
        # 创建数据库连接的副本用于线程
        db_path = self.parent.db_path
        
        # 创建工作线程
        worker = DataLoaderWorker(
            func=None,
            db_path=db_path,
            query_type='search_contracts',
            search_text=search_text
        )
        
        # 连接工作线程信号
        worker.signals.list_result.connect(self.onDataLoaded)
        worker.signals.error.connect(self.handleWorkerError)
        worker.signals.finished.connect(self.loading_finished)
        
        # 启动线程
        self.thread_pool.start(worker)
    
    def onLoadingStarted(self):
        """处理加载开始事件 - 优化版本，避免界面闪烁"""
        # 不隐藏表格，而是通过覆盖层显示加载指示器
        # 确保加载指示器可见且在最上层
        self.loading_indicator.raise_()
        self.loading_indicator.show()
        
        # 设置半透明背景，创建覆盖效果
        self.loading_indicator.setStyleSheet('font-size: 14px; color: #666; background-color: rgba(255, 255, 255, 0.8); border-radius: 4px; padding: 10px;')
    
    def onLoadingFinished(self):
        """处理加载完成事件 - 优化版本，实现平滑过渡"""
        # 延迟隐藏加载指示器，确保表格数据已经完全更新
        QTimer.singleShot(100, self.loading_indicator.hide)
    
    def handleWorkerError(self, error_info):
        """处理工作线程错误"""
        error, traceback_info = error_info
        QMessageBox.critical(self, "加载错误", f"加载数据时发生错误: {str(error)}")
    
    def onDataLoaded(self, contracts, db_path=None):
        """处理异步加载的数据 - 优化版本，减少UI闪烁"""
        import time
        start_time = time.time()
        
        # 获取当前日期和提醒设置
        today = datetime.now().date()
        # 提前获取提醒设置，避免多次调用
        contract_reminder_days, rent_reminder_days = self.parent.getReminderSettings()
        
        # 性能优化：阻止信号和更新，减少UI刷新
        self.contract_table.blockSignals(True)
        self.contract_table.setUpdatesEnabled(False)
        
        # 保存当前表格的滚动位置，以便数据更新后恢复
        scrollbar = self.contract_table.verticalScrollBar()
        current_scroll_pos = scrollbar.value()
        
        # 预先创建所有常用的颜色和字体对象，避免重复创建
        red_color = QColor(220, 53, 69)
        bright_red_color = QColor(255, 0, 0)  # 鲜红色，用于关键字高亮
        red_brush = QBrush(red_color)
        bright_red_brush = QBrush(bright_red_color)  # 鲜红色刷，用于关键字高亮
        alert_background = QBrush(QColor(255, 248, 248))
        yellow_background = QBrush(QColor(255, 255, 200))
        
        # 预先创建字体对象
        bold_font = QFont()
        bold_font.setBold(True)
        bold_font.setPointSize(13)  # 从11增加1个单位，原来是增加2个单位到14
        
        # 创建默认字体对象，比原来减少1个单位（从11减到10）
        default_font = QFont()
        default_font.setPointSize(10)
        
        # 创建关键字高亮专用的字体对象
        keyword_bold_font = QFont()
        keyword_bold_font.setBold(True)
        keyword_bold_font.setPointSize(10)  # 保持与默认字体相同大小，仅加粗
        
        # 定义关键字段列索引，避免重复创建列表
        urgent_key_cols = [0, 5, 11, 13, 15, 16, 17]  # 紧急样式关键字段
        active_key_cols = [0, 2, 5, 7, 8, 11, 13, 15, 16, 17]  # 执行中合同关键字段
        
        # 自定义排序函数:按房屋编号升序排列
        # 数值部分按0-9顺序,中文字符部分按首字母A-Z顺序
        def customSort(contract):
            house_no = contract[2] if len(contract) > 2 else ''
            house_no = str(house_no) if house_no is not None else ''
            
            # 提取数值部分
            num_part = ''
            for char in house_no:
                if char.isdigit():
                    num_part += char
                else:
                    break
            
            # 如果有数值部分,转换为整数,否则设为0
            num_value = int(num_part) if num_part else 0
            
            # 提取中文/非数值部分
            non_num_part = house_no[len(num_part):] if num_part else house_no
            
            # 返回一个元组作为排序键:(数值部分, 非数值部分)
            return (num_value, non_num_part)
        
        # 对合同数据进行排序
        sorted_contracts = sorted(contracts, key=customSort)
        
        # 批量处理：先计算所有需要的信息，再一次性填充表格
        # 准备所有数据行
        table_data = []
        for contract in sorted_contracts:
            # 计算各种数值 - 修正字段索引
            monthly_rent_value = 0.0
            try:
                # 正确索引：monthly_rent在查询结果中是第11个字段
                monthly_rent = contract[11] if 11 < len(contract) else 0
                if monthly_rent:
                    monthly_rent_value = float(monthly_rent)
            except (ValueError, TypeError):
                pass  # 保持默认值0.0
                
            annual_rent_value = 0
            try:
                # 正确索引：annual_rent在查询结果中是第14个字段
                annual_rent = contract[14] if 14 < len(contract) else 0
                if annual_rent:
                    annual_rent_value = round(float(annual_rent))
            except (ValueError, TypeError):
                pass  # 保持默认值0
                
            deposit_value = 0
            try:
                # 正确索引：deposit在查询结果中是第15个字段
                deposit = contract[15] if 15 < len(contract) else 0
                if deposit:
                    deposit_value = round(float(deposit))
            except (ValueError, TypeError):
                pass  # 保持默认值0
                
            received_rent = 0
            try:
                # 正确索引：received_rent在查询结果中是第16个字段（子查询）
                if len(contract) > 16:
                    rent_value = contract[16]  # 这是通过子查询计算的已收租金
                    if rent_value is not None:
                        received_rent = round(float(rent_value))
            except (ValueError, TypeError):
                pass  # 保持默认值0
                
            remaining_rent = annual_rent_value - received_rent
            remaining_rent = round(remaining_rent)
            payment_status = "未结清" if remaining_rent != 0 else "已结清"
            quarterly_rent = round(monthly_rent_value * 3) if monthly_rent_value else 0
            
            # 处理日期和状态
            end_date_str = contract[8] if len(contract) > 8 else None
            status = contract[9] if len(contract) > 9 else ""
            
            # 直接从查询结果获取季度租金（如果存在）
            quarterly_rent_value = 0
            try:
                # 正确索引：quarterly_rent在查询结果中是第12个字段
                if len(contract) > 12 and contract[12]:
                    quarterly_rent_value = round(float(contract[12]))
                else:
                    # 如果数据库中没有季度租金，则通过月租计算
                    quarterly_rent_value = round(monthly_rent_value * 3) if monthly_rent_value else 0
            except (ValueError, TypeError):
                # 计算失败时通过月租计算
                quarterly_rent_value = round(monthly_rent_value * 3) if monthly_rent_value else 0
            
            # 预计算日期相关信息，避免重复解析
            is_urgent = False
            days_left = None
            
            if end_date_str and status == '执行中':
                try:
                    end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                    days_left = (end_date - today).days
                    is_urgent = days_left <= contract_reminder_days
                except ValueError:
                    log_error(f"日期格式错误: {end_date_str}")
                    
            # 存储所有计算结果
            table_data.append({
                'contract': contract,
                'monthly_rent_value': monthly_rent_value,
                'annual_rent_value': annual_rent_value,
                'deposit_value': deposit_value,
                'received_rent': received_rent,
                'remaining_rent': remaining_rent,
                'payment_status': payment_status,
                'quarterly_rent': quarterly_rent_value,
                'end_date_str': end_date_str,
                'status': status,
                'is_urgent': is_urgent,
                'days_left': days_left
            })
        
        # 清空表格
        self.contract_table.setRowCount(0)
        self.contract_table.setSortingEnabled(False)  # 禁用排序以提高性能
        
        # 存储所有数据到缓存
        self.all_contract_data = table_data.copy()
        
        # 一次性设置表格行数，显示所有数据
        self.contract_table.setRowCount(len(table_data))
        
        # 优化版表格数据填充 - 批量创建和设置单元格
        for row_idx, data in enumerate(table_data):
            contract = data['contract']
            
            # 获取搜索文本，用于关键字高亮
            search_text = getattr(self, 'search_input', None)
            if search_text:
                search_text = search_text.text().strip()
            else:
                search_text = ''
            
            # 预先创建和设置所有基本列的单元格
            # 使用元组定义列配置：(列索引, 数据索引, 对齐方式)
            basic_cols = [
                (0, 0, Qt.AlignCenter),    # 合同编号
                (1, 1, Qt.AlignCenter),    # 签约日期
                (2, 2, Qt.AlignCenter),    # 房屋编号
                (3, 3, Qt.AlignCenter),    # 房屋类型
                (4, 4, Qt.AlignCenter),    # 房屋位置
                (5, 5, Qt.AlignCenter),    # 承租方
                (6, 6, Qt.AlignCenter),    # 承租人
                (7, 7, Qt.AlignCenter),    # 租赁开始日期
                (8, 8, Qt.AlignCenter),    # 租赁截止日期
                (9, 9, Qt.AlignCenter),    # 合同状态
                (10, 10, Qt.AlignCenter)   # 租金支付方式
            ]
            
            # 批量设置基本列
            for col_idx, data_idx, alignment in basic_cols:
                if data_idx < len(contract):
                    value = contract[data_idx]
                    if value is not None:
                        text_value = str(value)
                        item = QTableWidgetItem(text_value)
                        item.setTextAlignment(alignment)
                        
                        # 如果搜索文本不为空，且单元格文本包含搜索文本，则应用关键字高亮样式
                        if search_text and search_text.lower() in text_value.lower():
                            # 设置加粗和鲜红色
                            item.setFont(keyword_bold_font)
                            item.setForeground(bright_red_brush)
                        else:
                            item.setFont(default_font)
                        
                        self.contract_table.setItem(row_idx, col_idx, item)
                    else:
                        # 为None值设置空单元格
                        item = QTableWidgetItem('')
                        item.setTextAlignment(alignment)
                        item.setFont(default_font)
                        self.contract_table.setItem(row_idx, col_idx, item)
            
            # 优化版金额列设置 - 使用预计算数据和批量处理
            
            # 使用前面已经计算好的数据，避免重复计算
            monthly_rent_value = data['monthly_rent_value']
            quarterly_rent_value = data['quarterly_rent']
            annual_rent_value = data['annual_rent_value']
            deposit_value = data['deposit_value']
            received_rent_value = data['received_rent']
            remaining_rent_value = data['remaining_rent']
            payment_status_value = data['payment_status']
            
            # 定义金额列的格式化和显示配置
            amount_cols = [
                (11, monthly_rent_value, ',.2f'),  # 月租金额
                (12, quarterly_rent_value, ',.0f'), # 季度租金
                (13, annual_rent_value, ',.0f'),    # 年租金总额
                (14, deposit_value, ',.0f'),        # 押金金额
                (15, received_rent_value, ',.0f'),  # 已收总租金
                (16, remaining_rent_value, ',.0f')  # 应收总租金
            ]
            
            # 批量设置金额列
            for col_idx, value, format_spec in amount_cols:
                formatted_value = f"{value:{format_spec}}"
                item = QTableWidgetItem(formatted_value)
                item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                
                # 为金额列也应用关键字高亮
                if search_text and search_text.lower() in formatted_value.lower():
                    item.setFont(keyword_bold_font)
                    item.setForeground(bright_red_brush)
                else:
                    item.setFont(default_font)
                    
                self.contract_table.setItem(row_idx, col_idx, item)
            
            # 设置收款情况列（最后一列）
            item = QTableWidgetItem(payment_status_value)
            item.setTextAlignment(Qt.AlignCenter)
            
            # 为收款情况列也应用关键字高亮
            if search_text and search_text.lower() in payment_status_value.lower():
                item.setFont(keyword_bold_font)
                item.setForeground(bright_red_brush)
            else:
                item.setFont(default_font)
                
            self.contract_table.setItem(row_idx, 17, item)
            
            # 优化版样式应用 - 减少重复设置和数据查询
            
            # 配置化的条件格式规则定义 - 清晰定义每个规则的条件、样式和优先级
            # 规则按优先级降序排列，优先级数字越小，优先级越高
            style_rules = [
                {
                    'name': 'urgent',
                    'priority': 1,
                    'condition': lambda d: d['payment_status'] == "未结清" and d['status'] == "执行中" and d['is_urgent'],
                    'target_columns': urgent_key_cols,
                    'style': {
                        'font': bold_font,
                        'foreground': red_brush,
                        'foreground_color': red_color,
                        'background': alert_background,
                        'background_color': QColor(255, 248, 248)
                    }
                },
                {
                    'name': 'active',
                    'priority': 2,
                    'condition': lambda d: d['status'] == "执行中",
                    'target_columns': active_key_cols,
                    'style': {
                        'background': yellow_background,
                        'background_color': QColor(255, 255, 200)
                    }
                },
                {
                    'name': 'overdue',
                    'priority': 3,
                    'condition': lambda d: d['status'] == "已逾期",
                    'target_columns': active_key_cols,
                    'style': {
                        'font': bold_font,
                        'foreground': red_brush,
                        'foreground_color': red_color,
                        'background': QBrush(QColor(255, 107, 107)),
                        'background_color': QColor(255, 107, 107)
                    }
                }
            ]
            
            # 应用条件格式规则 - 实现规则优先级机制
            applied_rule = None
            
            # 按优先级顺序检查规则
            for rule in sorted(style_rules, key=lambda r: r['priority']):
                if rule['condition'](data):
                    applied_rule = rule
                    log_debug(f"应用规则 '{rule['name']}' 到行 {row_idx}")
                    break
            
            # 检查是否为深色主题
            is_dark_theme = hasattr(self.parent, 'styleSheet') and 'dark' in self.parent.styleSheet().lower()
            
            # 如果找到匹配的规则，应用相应样式
            if applied_rule:
                # 批量应用样式到目标列
                for col_idx in applied_rule['target_columns']:
                    cell_item = self.contract_table.item(row_idx, col_idx)
                    if cell_item:
                        # 只设置规则中定义的样式属性，避免不必要的样式设置
                        style = applied_rule['style']
                        
                        # 深拷贝样式字典，避免修改原始样式定义
                        theme_adjusted_style = style.copy()
                        
                        # 根据主题调整颜色
                        if is_dark_theme:
                            # 根据规则名称调整深色主题下的颜色
                            if applied_rule['name'] == 'urgent':
                                # 紧急状态 - 深色主题调整
                                theme_adjusted_style['foreground_color'] = QColor(255, 100, 100)  # 亮红色文本
                                theme_adjusted_style['background_color'] = QColor(60, 30, 30)    # 深红色背景
                                # 移除可能导致冲突的brush设置
                                if 'foreground' in theme_adjusted_style:
                                    del theme_adjusted_style['foreground']
                                if 'background' in theme_adjusted_style:
                                    del theme_adjusted_style['background']
                            elif applied_rule['name'] == 'active':
                                # 执行中状态 - 深色主题调整
                                theme_adjusted_style['background_color'] = QColor(30, 30, 60)    # 深蓝色背景
                                # 移除可能导致冲突的brush设置
                                if 'background' in theme_adjusted_style:
                                    del theme_adjusted_style['background']
                            elif applied_rule['name'] == 'overdue':
                                # 已逾期状态 - 深色主题调整
                                theme_adjusted_style['foreground_color'] = QColor(255, 255, 100)  # 亮黄色文本
                                theme_adjusted_style['background_color'] = QColor(60, 60, 30)    # 深黄色背景
                                # 移除可能导致冲突的brush设置
                                if 'foreground' in theme_adjusted_style:
                                    del theme_adjusted_style['foreground']
                                if 'background' in theme_adjusted_style:
                                    del theme_adjusted_style['background']
                        
                        # 使用字典映射批量应用样式，提高执行效率
                        # 使用setForeground和setBackground方法，确保样式优先级高于QSS样式
                        style_apply_map = {
                            'font': lambda item, value: item.setFont(value),
                            'foreground_color': lambda item, value: item.setForeground(QBrush(value)),
                            'background_color': lambda item, value: item.setBackground(QBrush(value))
                        }
                        
                        # 应用每个样式属性
                        for prop, apply_func in style_apply_map.items():
                            if prop in theme_adjusted_style:
                                apply_func(cell_item, theme_adjusted_style[prop])
            
            # 优化：添加额外的视觉反馈 - 根据剩余天数显示不同的视觉提示
            if data['days_left'] is not None and data['status'] == "执行中":
                # 在截止日期列添加特殊标记
                deadline_col = 8  # 租赁截止日期列索引
                deadline_item = self.contract_table.item(row_idx, deadline_col)
                if deadline_item:
                    # 根据剩余天数设置不同的样式
                    if data['days_left'] <= 7:
                        # 7天内到期 - 红色警告
                        deadline_item.setFont(bold_font)
                        if is_dark_theme:
                            # 深色主题使用亮红色
                            deadline_item.setForeground(QBrush(QColor(255, 100, 100)))
                        else:
                            deadline_item.setForeground(QBrush(red_color))
                    elif data['days_left'] <= 30:
                        # 30天内到期 - 橙色提示
                        if is_dark_theme:
                            # 深色主题使用亮橙色
                            deadline_item.setForeground(QBrush(QColor(255, 200, 100)))
                        else:
                            warning_color = QColor(255, 165, 0)
                            deadline_item.setForeground(QBrush(warning_color))
        
        # 优化：先恢复更新和信号，但延迟启用排序
        self.contract_table.setUpdatesEnabled(True)
        self.contract_table.blockSignals(False)
        
        # 使用优化的列宽调整方法
        self.optimize_column_widths()
        
        # 在所有设置完成后启用排序
        self.contract_table.setSortingEnabled(True)
        
        # 恢复滚动位置，避免视图跳跃
        scrollbar.setValue(min(current_scroll_pos, scrollbar.maximum()))
        
    def optimize_column_widths(self):
        """实现合同列表的列宽自动适应功能 - 根据内容智能调整列宽"""
        # 先禁用表格更新以提高性能
        self.contract_table.setUpdatesEnabled(False)
        
        # 定义每列的最小宽度和最大宽度
        # 确保不会出现过窄或过宽的列
        min_widths = {
            0: 120,  # 合同编号
            1: 100,  # 签约日期
            2: 80,   # 房屋编号
            3: 80,   # 房屋类型
            4: 150,  # 房屋位置
            5: 180,  # 承租方
            6: 100,  # 承租人
            7: 100,  # 租赁开始日期
            8: 100,  # 租赁截止日期
            9: 80,   # 合同状态
            10: 120, # 租金支付方式
            11: 100, # 月租金额
            12: 100, # 季度租金
            13: 120, # 年租金总额
            14: 100, # 押金金额
            15: 120, # 已收总租金
            16: 120, # 应收总租金
            17: 100  # 收款情况
        }
        
        max_widths = {
            0: 200,  # 合同编号
            1: 120,  # 签约日期
            2: 100,  # 房屋编号
            3: 100,  # 房屋类型
            4: 300,  # 房屋位置
            5: 350,  # 承租方
            6: 150,  # 承租人
            7: 120,  # 租赁开始日期
            8: 120,  # 租赁截止日期
            9: 100,  # 合同状态
            10: 150, # 租金支付方式
            11: 120, # 月租金额
            12: 120, # 季度租金
            13: 150, # 年租金总额
            14: 120, # 押金金额
            15: 150, # 已收总租金
            16: 150, # 应收总租金
            17: 120  # 收款情况
        }
        
        # 为所有列应用自动适应宽度
        for col in range(self.contract_table.columnCount()):
            # 为每列设置初始的固定模式，避免在计算过程中不断重绘
            self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Interactive)
            
            # 临时设置为自适应内容以获取所需宽度
            self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.ResizeToContents)
            
            # 获取自适应后的宽度
            content_width = self.contract_table.columnWidth(col)
            
            # 获取列标题的宽度
            header_width = self.contract_table.horizontalHeader().sectionSizeHint(col)
            
            # 计算最终宽度：取内容宽度、标题宽度和最小宽度的最大值，但不超过最大宽度
            min_width = min_widths.get(col, 80)
            max_width = max_widths.get(col, 250)
            final_width = max(content_width, header_width, min_width)
            final_width = min(final_width, max_width)
            
            # 设置最终宽度
            self.contract_table.setColumnWidth(col, final_width)
            
            # 对超长文本列设置省略号显示
            if final_width >= max_width * 0.9:  # 接近最大宽度时设置省略号
                for row in range(min(self.contract_table.rowCount(), 100)):  # 只处理前100行，避免性能问题
                    item = self.contract_table.item(row, col)
                    if item:
                        item.setTextAlignment(item.textAlignment() | Qt.TextElideMode.ElideRight)
            
            # 设置回固定模式，保持布局稳定性
            self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Fixed)
        
        # 为最后一列设置适当宽度，确保整体布局美观
        last_col = self.contract_table.columnCount() - 1
        if last_col >= 0:
            # 计算剩余可用空间
            table_width = self.contract_table.viewport().width()
            used_width = sum(self.contract_table.columnWidth(col) for col in range(last_col))
            remaining_width = max(0, table_width - used_width - 20)  # 减去20作为边距
            
            # 如果有剩余空间，合理分配给最后一列
            if remaining_width > 0:
                current_width = self.contract_table.columnWidth(last_col)
                max_final_width = max_widths.get(last_col, 250)
                new_width = min(current_width + remaining_width, max_final_width)
                self.contract_table.setColumnWidth(last_col, new_width)
            
            # 最后一列使用固定模式，避免在窗口调整时剧烈变化
            self.contract_table.horizontalHeader().setSectionResizeMode(last_col, QHeaderView.Fixed)
        
        # 重新启用表格更新
        self.contract_table.setUpdatesEnabled(True)
        
        # 强制重绘表格
        self.contract_table.viewport().update()
        
        # 更新统计信息
        # 直接调用updateStatistics方法，不需要数据库连接，因为现在统计基于表格数据
        self.updateStatistics()
        
        # 记录性能日志
        log_info(f"合同数据加载完成")
    

        
    def updateStatistics(self, conn=None):
        """优化版统计方法 - 基于表格中当前显示的数据进行统计，确保统计数据与搜索结果一致"""
        try:
            # 初始化统计变量
            total_contracts = 0
            active_contracts = 0
            completed_contracts = 0
            overdue_contracts = 0
            monthly_total = 0.0
            quarterly_total = 0.0
            annual_total = 0.0
            deposit_total = 0.0
            received_total = 0.0
            settled_count = 0
            unsettled_count = 0
            
            # 获取当前日期用于判断逾期
            today = datetime.now().date()
            
            # 遍历表格中的所有行进行统计
            for row in range(self.contract_table.rowCount()):
                total_contracts += 1
                
                # 获取合同状态（第9列）
                status_item = self.contract_table.item(row, 9)
                status = status_item.text() if status_item else ''
                
                # 计算状态统计
                if status == '执行中':
                    active_contracts += 1
                    # 检查是否逾期
                    end_date_item = self.contract_table.item(row, 8)
                    if end_date_item and end_date_item.text():
                        try:
                            end_date_str = end_date_item.text()
                            # 处理不同格式的日期
                            date_formats = ['%Y-%m-%d', '%Y/%m/%d', '%d-%m-%Y', '%d/%m/%Y']
                            end_date = None
                            for fmt in date_formats:
                                try:
                                    end_date = datetime.strptime(end_date_str, fmt).date()
                                    break
                                except ValueError:
                                    continue
                            
                            if end_date and end_date < today:
                                overdue_contracts += 1
                        except Exception:
                            pass  # 日期解析失败，跳过逾期检查
                elif status == '已完成':
                    completed_contracts += 1
                elif status == '已逾期':
                    overdue_contracts += 1
                
                # 获取月租金额（第11列）
                monthly_rent_item = self.contract_table.item(row, 11)
                if monthly_rent_item and monthly_rent_item.text():
                    try:
                        # 移除货币符号和逗号等非数字字符
                        clean_text = ''.join(c for c in monthly_rent_item.text() if c.isdigit() or c == '.')
                        monthly_rent = float(clean_text)
                        monthly_total += monthly_rent
                        quarterly_total += monthly_rent * 3
                    except ValueError:
                        pass
                
                # 获取年租金总额（第13列）
                annual_rent_item = self.contract_table.item(row, 13)
                if annual_rent_item and annual_rent_item.text():
                    try:
                        # 移除货币符号和逗号等非数字字符
                        clean_text = ''.join(c for c in annual_rent_item.text() if c.isdigit() or c == '.')
                        annual_rent = float(clean_text)
                        annual_total += annual_rent
                    except ValueError:
                        pass
                
                # 获取押金金额（第14列）
                deposit_item = self.contract_table.item(row, 14)
                if deposit_item and deposit_item.text():
                    try:
                        # 移除货币符号和逗号等非数字字符
                        clean_text = ''.join(c for c in deposit_item.text() if c.isdigit() or c == '.')
                        deposit = float(clean_text)
                        deposit_total += deposit
                    except ValueError:
                        pass
                
                # 获取已收总租金（第15列）
                received_item = self.contract_table.item(row, 15)
                if received_item and received_item.text():
                    try:
                        # 移除货币符号和逗号等非数字字符
                        clean_text = ''.join(c for c in received_item.text() if c.isdigit() or c == '.')
                        received = float(clean_text)
                        received_total += received
                    except ValueError:
                        pass
                
                # 判断是否已结清（根据第17列收款情况）
                payment_status_item = self.contract_table.item(row, 17)
                if payment_status_item and payment_status_item.text():
                    payment_status = payment_status_item.text()
                    if payment_status == '已结清':
                        settled_count += 1
                    elif payment_status == '未结清':
                        unsettled_count += 1
            
            # 计算应收总租金，确保不会为负数
            receivable_total = max(0, annual_total - received_total)
            
            # 更新统计标签
            self.total_count_label.setText(f'合计笔数: {total_contracts}')
            # 添加合同状态统计标签更新
            self.total_contracts_label.setText(f'合同总数: {total_contracts}')
            self.active_contracts_label.setText(f'执行中合同: {active_contracts}')
            self.completed_contracts_label.setText(f'已完成合同: {completed_contracts}')
            self.overdue_contracts_label.setText(f'逾期合同: {overdue_contracts}')
            # 其他统计标签更新
            self.monthly_total_label.setText(f'月总租金: ¥{monthly_total:,.2f}')
            self.quarterly_total_label.setText(f'季总租金: ¥{round(quarterly_total):,.0f}')
            self.annual_total_label.setText(f'年总租金: ¥{round(annual_total):,.0f}')
            self.deposit_total_label.setText(f'押金总金额: ¥{round(deposit_total):,.0f}')
            self.received_total_label.setText(f'已收总租金: ¥{round(received_total):,.0f}')
            self.receivable_total_label.setText(f'应收总租金: ¥{round(receivable_total):,.0f}')
            self.unsettled_count_label.setText(f'未结清笔数: {unsettled_count}')
            self.settled_count_label.setText(f'已结清笔数: {settled_count}')
            
        except Exception as e:
            log_error(f"更新统计数据时出错: {str(e)}")
            # 出错时显示默认值
            self.total_count_label.setText('合计笔数: 0')
            # 合同状态统计标签默认值
            self.total_contracts_label.setText('合同总数: 0')
            self.active_contracts_label.setText('执行中合同: 0')
            self.completed_contracts_label.setText('已完成合同: 0')
            self.overdue_contracts_label.setText('逾期合同: 0')
            # 其他统计标签默认值
            self.monthly_total_label.setText('月总租金: ¥0.00')
            self.quarterly_total_label.setText('季总租金: ¥0')
            self.annual_total_label.setText('年总租金: ¥0')
            self.deposit_total_label.setText('押金总金额: ¥0')
            self.received_total_label.setText('已收总租金: ¥0')
            self.receivable_total_label.setText('应收总租金: ¥0')
            self.unsettled_count_label.setText('未结清笔数: 0')
            self.settled_count_label.setText('已结清笔数: 0')
    

    
    def onCellClicked(self, row, col):
        # 当单元格被点击时启用编辑和删除按钮
        self.edit_button.setEnabled(True)
        self.delete_button.setEnabled(True)
        self.payment_details_button.setEnabled(True)
        
    def onCellDoubleClicked(self, row, col):
        # 当单元格被双击时打开编辑合同窗口
        # 设置当前选中行
        self.contract_table.selectRow(row)
        # 调用编辑合同方法
        self.editContract()
        
    def showPaymentDetails(self):
        """显示所选合同的收款明细"""
        # 获取选中的合同编号
        selected_rows = self.contract_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.information(self, '提示', '请先选择一条合同记录')
            return
        
        selected_row = selected_rows[0].row()
        contract_no_item = self.contract_table.item(selected_row, 0)
        if not contract_no_item:
            return
        
        contract_no = contract_no_item.text()
        
        # 创建收款明细对话框
        dialog = QDialog(self)
        dialog.setWindowTitle(f'合同 {contract_no} 收款明细')
        dialog.resize(900, 500)
        
        # 创建主布局
        main_layout = QVBoxLayout(dialog)
        
        # 创建收款明细表格
        payment_table = QTableWidget()
        payment_table.setColumnCount(8)
        payment_table.setHorizontalHeaderLabels(['收款日期', '收款金额', '所属期间开始', '所属期间截止', '收款账户', '发票收据日期', '承租方', '说明'])
        payment_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        payment_table.setEditTriggers(QTableWidget.NoEditTriggers)
        payment_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 加载收款明细数据
        try:
            # 连接数据库
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                raise Exception("无法获取数据库连接")
            cursor = conn.cursor()
            
            # 查询收款明细数据
            cursor.execute("""
                SELECT receipt_date, amount, period_start, period_end, account, invoice_date, lessee, description 
                FROM rent_records 
                WHERE contract_no = ? 
                ORDER BY receipt_date DESC
            """, (contract_no,))
            payment_records = cursor.fetchall()
            
            # 查询合同年租金总额
            cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
            contract_result = cursor.fetchone()
            annual_rent = float(contract_result[0]) if contract_result and contract_result[0] is not None else 0
            
            # 填充表格
            payment_table.setRowCount(len(payment_records))
            for row_idx, record in enumerate(payment_records):
                # 收款日期
                item = QTableWidgetItem(str(record[0]) if record[0] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                payment_table.setItem(row_idx, 0, item)
                
                # 收款金额
                try:
                    amount_value = float(record[1]) if record[1] is not None else 0
                    item = QTableWidgetItem(f'{amount_value:,.2f}')
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                except (ValueError, TypeError):
                    item = QTableWidgetItem(str(record[1]) if record[1] is not None else '')
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                payment_table.setItem(row_idx, 1, item)
                
                # 所属期间开始
                item = QTableWidgetItem(str(record[2]) if record[2] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                payment_table.setItem(row_idx, 2, item)
                
                # 所属期间截止
                item = QTableWidgetItem(str(record[3]) if record[3] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                payment_table.setItem(row_idx, 3, item)
                
                # 收款账户
                item = QTableWidgetItem(str(record[4]) if record[4] is not None else '')
                item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
                payment_table.setItem(row_idx, 4, item)
                
                # 发票收据日期
                item = QTableWidgetItem(str(record[5]) if record[5] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                payment_table.setItem(row_idx, 5, item)
                
                # 承租方
                item = QTableWidgetItem(str(record[6]) if record[6] is not None else '')
                item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
                payment_table.setItem(row_idx, 6, item)
                
                # 说明
                item = QTableWidgetItem(str(record[7]) if record[7] is not None else '')
                item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
                payment_table.setItem(row_idx, 7, item)
            
            # 计算收款总额
            total_amount = sum(float(record[1]) for record in payment_records if record[1] is not None)
            
            # 计算应收租金余额，确保不会为负数
            remaining_rent = max(0, annual_rent - total_amount)
            
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载收款明细数据时发生错误:\n{str(e)}')
            log_error(f'加载收款明细数据时发生错误:{str(e)}')
            return
        
        # 添加表格到布局
        main_layout.addWidget(payment_table)
        
        # 创建统计信息区域
        stats_layout = QHBoxLayout()
        stats_layout.setContentsMargins(10, 10, 10, 10)
        
        # 显示年租金总额
        annual_rent_label = QLabel(f'年租金总额: ¥{annual_rent:,.2f}')
        font = QFont()
        font.setPointSize(11)
        font.setBold(True)
        annual_rent_label.setFont(font)
        stats_layout.addWidget(annual_rent_label)
        
        # 显示收款总额
        total_label = QLabel(f'收款总额: ¥{total_amount:,.2f}')
        total_label.setFont(font)
        stats_layout.addWidget(total_label)
        
        # 显示应收租金余额
        remaining_label = QLabel(f'应收租金余额: ¥{remaining_rent:,.2f}')
        remaining_label.setFont(font)
        stats_layout.addWidget(remaining_label)
        
        # 添加统计信息区域到主布局
        main_layout.addLayout(stats_layout)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 关闭按钮
        close_button = QPushButton('关闭')
        close_button.clicked.connect(dialog.accept)
        button_layout.addWidget(close_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 执行对话框
        dialog.exec_()
    
    def resetSearch(self):
        """
        重置搜索框并显示所有记录
        
        功能: 清空搜索输入框内容,并执行搜索功能以显示所有记录
        """
        self.search_input.clear()
        self.searchContracts()
    
    def addContract(self):
        """
        添加新合同
        
        功能: 创建新的租赁合同,包括收集合同信息、计算租金相关数据、保存到数据库
        
        实现步骤:
            1. 显示合同信息填写对话框
            2. 收集用户填写的合同数据
            3. 计算签约年月、年租金总额、租金收款总额等派生数据
            4. 将合同数据保存到数据库
            5. 重新加载合同列表,显示最新数据
            6. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、数据格式异常等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始添加新合同")
            
            # 添加合同
            dialog = ContractDialog()
            if dialog.exec_():
                # 保存合同数据
                contract_data = dialog.getContractData()
                log_debug(f"获取到合同数据: {contract_data['contract_no']}")
                
                # 连接数据库并插入数据
                from db_utils import DatabaseUtils
                conn = None
                cursor = None
                
                try:
                    conn = DatabaseUtils.get_connection()
                    if not conn:
                        raise Exception("无法获取数据库连接")
                    cursor = conn.cursor()
                    
                    # 计算签约年月
                    try:
                        sign_date = datetime.strptime(contract_data['sign_date'], '%Y-%m-%d')
                        sign_year_month = f"{sign_date.year}-{sign_date.month:02d}"
                        log_debug(f"计算签约年月: {sign_year_month}")
                    except ValueError as e:
                        log_error(f"日期格式错误: {str(e)}")
                        QMessageBox.warning(self, '日期格式错误', '请检查签约日期格式是否正确!')
                        return
                    
                    # 计算年租金总额
                    monthly_rent = contract_data['monthly_rent']
                    annual_rent = monthly_rent * 12
                    log_debug(f"计算年租金总额: {annual_rent}")
                    
                    # 计算租金收款总额
                    try:
                        start_date = datetime.strptime(contract_data['start_date'], '%Y-%m-%d')
                        end_date = datetime.strptime(contract_data['end_date'], '%Y-%m-%d')
                        months = (end_date.year - start_date.year) * 12 + (end_date.month - start_date.month)
                        total_rent = monthly_rent * months
                        log_debug(f"计算租金收款总额: {total_rent}")
                    except ValueError as e:
                        log_error(f"日期格式错误: {str(e)}")
                        QMessageBox.warning(self, '日期格式错误', '请检查起租日期或到期日期格式是否正确!')
                        return
                    
                    # 插入数据
                    try:
                        cursor.execute(
                            '''INSERT INTO contracts (
                                contract_no, sign_date, sign_year_month, house_no, house_location, house_area, 
                                lessor, legal_representative, person_in_charge, contact_phone, 
                                lessee, tenant, tenant_id, tenant_phone, 
                                start_date, end_date, status, payment_method, monthly_rent, 
                                total_rent, annual_rent, deposit, usage, utility_method, water_fee, electricity_fee, 
                                remarks, quarterly_rent, house_type, attachment_path, payment_status
                            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                            (
                                contract_data['contract_no'], contract_data['sign_date'], sign_year_month,
                                contract_data['house_no'], contract_data['house_location'], contract_data['house_area'],
                                contract_data['lessor'], contract_data['legal_representative'], contract_data['person_in_charge'], contract_data['contact_phone'],
                                contract_data['lessee'], contract_data['tenant'], contract_data['tenant_id'], contract_data['tenant_phone'],
                                contract_data['start_date'], contract_data['end_date'], contract_data['status'], contract_data['payment_method'],
                                contract_data['monthly_rent'], total_rent, annual_rent, contract_data['deposit'],
                                contract_data['usage'], contract_data['utility_method'], contract_data['water_fee'], contract_data['electricity_fee'],
                                contract_data['remarks'], contract_data['quarterly_rent'], contract_data['house_type'], contract_data['attachment_path'], contract_data['payment_status']
                            )
                        )
                        log_debug(f"成功执行合同数据插入SQL")
                        
                        # 提交事务
                        conn.commit()
                        log_info(f"成功添加合同: {contract_data['contract_no']}")
                        
                        # 记录操作日志 - 操作成功
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="添加合同",
                            operation_result="成功",
                            detail=f"合同编号: {contract_data['contract_no']}, 租户: {contract_data['lessee']}"
                        )
                        
                        # 显示成功消息
                        QMessageBox.information(self, '添加成功', f"合同编号为【{contract_data['contract_no']}】的合同添加成功!")
                    except sqlite3.IntegrityError as e:
                        conn.rollback()
                        log_error(f"合同数据完整性错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="添加合同",
                            operation_result="失败",
                            detail=f"合同编号: {contract_data['contract_no']}, 错误信息: {str(e)}"
                        )
                        
                        QMessageBox.warning(self, '添加失败', f'合同编号已存在或数据不完整!\n错误信息: {str(e)}')
                        return
                    except sqlite3.Error as e:
                        conn.rollback()
                        log_error(f"数据库错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="添加合同",
                            operation_result="失败",
                            detail=f"合同编号: {contract_data['contract_no']}, 错误信息: {str(e)}"
                        )
                        
                        QMessageBox.warning(self, '添加失败', f'数据库操作失败!\n错误信息: {str(e)}')
                        return
                finally:
                    # 关闭数据库连接
                    if cursor:
                        cursor.close()
                    if conn:
                        DatabaseUtils.close_connection(conn)
                    log_debug("数据库连接已关闭")
                
                # 重新加载合同数据
                try:
                    self.loadContracts()
                    log_debug("合同列表已更新")
                except Exception as e:
                    log_error(f"重新加载合同数据失败: {str(e)}")
                
                # 发送数据更新信号
                self.data_updated.emit()
                log_debug("发送数据更新信号")
        except Exception as e:
            log_error(f"添加合同过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="合同管理",
                operation_content="添加合同",
                operation_result="异常",
                detail=f"错误信息: {str(e)}"
            )
            
            QMessageBox.critical(self, '系统错误', f'添加合同失败!\n错误信息: {str(e)}')
    
    def editContract(self):
        """
        编辑现有合同
        
        功能: 修改已存在的租赁合同信息,包括获取当前合同数据、显示编辑对话框、保存更新后的信息
        
        实现步骤:
            1. 检查是否选择了要编辑的合同
            2. 获取选中合同的合同编号
            3. 从数据库中获取该合同的详细信息
            4. 显示编辑对话框并填充现有数据
            5. 收集用户修改后的合同数据
            6. 重新计算租金相关派生数据
            7. 更新数据库中的合同信息
            8. 重新加载合同列表,显示最新数据
            9. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、数据格式异常、合同不存在等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始编辑合同")
            
            # 编辑合同
            selected_rows = self.contract_table.selectionModel().selectedRows()
            if not selected_rows:
                log_warning("用户未选择要编辑的合同")
                QMessageBox.warning(self, '警告', '请先选择要编辑的合同!')
                return
            
            row = selected_rows[0].row()
            contract_no = self.contract_table.item(row, 0).text()
            log_debug(f"选择的合同编号: {contract_no}")
            
            # 连接数据库并获取合同详细信息
            from db_utils import DatabaseUtils
            conn = None
            cursor = None
            contract = None
            
            try:
                conn = DatabaseUtils.get_connection()
                if not conn:
                    raise Exception("无法获取数据库连接")
                cursor = conn.cursor()
                cursor.execute("SELECT * FROM contracts WHERE contract_no = ?", (contract_no,))
                contract = cursor.fetchone()
                log_debug(f"成功获取合同详细信息: {contract_no}")
            except sqlite3.Error as e:
                log_error(f"获取合同详细信息失败: {str(e)}")
                QMessageBox.warning(self, '查询失败', f'获取合同信息时出错!\n错误信息: {str(e)}')
                return
            finally:
                if cursor:
                    cursor.close()
                if conn:
                    DatabaseUtils.close_connection(conn)
                log_debug("数据库连接已关闭")
            
            if not contract:
                log_error(f"找不到合同: {contract_no}")
                QMessageBox.warning(self, '警告', '找不到该合同的详细信息!')
                return
            
            # 创建对话框并填充数据
            dialog = ContractDialog(is_edit=True, contract_data=contract)
            if dialog.exec_():
                # 保存编辑后的合同数据
                contract_data = dialog.getContractData()
                log_debug(f"获取到更新后的合同数据: {contract_no}")
                
                # 连接数据库并更新数据
                try:
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    
                    # 计算签约年月
                    try:
                        sign_date = datetime.strptime(contract_data['sign_date'], '%Y-%m-%d')
                        sign_year_month = f"{sign_date.year}-{sign_date.month:02d}"
                        log_debug(f"计算签约年月: {sign_year_month}")
                    except ValueError as e:
                        log_error(f"日期格式错误: {str(e)}")
                        QMessageBox.warning(self, '日期格式错误', '请检查签约日期格式是否正确!')
                        return
                    
                    # 计算年租金总额
                    monthly_rent = contract_data['monthly_rent']
                    annual_rent = monthly_rent * 12
                    log_debug(f"计算年租金总额: {annual_rent}")
                    
                    # 计算租金收款总额
                    try:
                        start_date = datetime.strptime(contract_data['start_date'], '%Y-%m-%d')
                        end_date = datetime.strptime(contract_data['end_date'], '%Y-%m-%d')
                        months = (end_date.year - start_date.year) * 12 + (end_date.month - start_date.month)
                        total_rent = monthly_rent * months
                        log_debug(f"计算租金收款总额: {total_rent}")
                    except ValueError as e:
                        log_error(f"日期格式错误: {str(e)}")
                        QMessageBox.warning(self, '日期格式错误', '请检查起租日期或到期日期格式是否正确!')
                        return
                    
                    # 更新数据
                    try:
                        cursor.execute(
                            '''UPDATE contracts SET 
                                sign_date = ?, sign_year_month = ?, house_no = ?, house_location = ?, house_area = ?, 
                                lessor = ?, legal_representative = ?, person_in_charge = ?, contact_phone = ?, 
                                lessee = ?, tenant = ?, tenant_id = ?, tenant_phone = ?, 
                                start_date = ?, end_date = ?, status = ?, payment_method = ?, monthly_rent = ?, total_rent = ?, annual_rent = ?, deposit = ?, 
                                usage = ?, utility_method = ?, water_fee = ?, electricity_fee = ?, remarks = ?, attachment_path = ? 
                            WHERE contract_no = ?''',
                            (
                                contract_data['sign_date'], sign_year_month,
                                contract_data['house_no'], contract_data['house_location'], contract_data['house_area'],
                                contract_data['lessor'], contract_data['legal_representative'], contract_data['person_in_charge'], contract_data['contact_phone'],
                                contract_data['lessee'], contract_data['tenant'], contract_data['tenant_id'], contract_data['tenant_phone'],
                                contract_data['start_date'], contract_data['end_date'], contract_data['status'], contract_data['payment_method'],
                                contract_data['monthly_rent'], total_rent, annual_rent, contract_data['deposit'],
                                contract_data['usage'], contract_data['utility_method'], contract_data['water_fee'], contract_data['electricity_fee'],
                                contract_data['remarks'], contract_data['attachment_path'], contract_no
                            )
                        )
                        log_debug(f"成功执行合同数据更新SQL")
                        
                        # 提交事务
                        conn.commit()
                        log_info(f"成功更新合同: {contract_no}")
                        
                        # 记录操作日志 - 操作成功
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="编辑合同",
                            operation_result="成功",
                            detail=f"合同编号: {contract_no}, 租户: {contract_data['lessee']}"
                        )
                        
                        # 显示成功消息
                        QMessageBox.information(self, '更新成功', f'合同编号为【{contract_no}】的合同更新成功!')
                    except sqlite3.IntegrityError as e:
                        conn.rollback()
                        log_error(f"合同数据完整性错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="编辑合同",
                            operation_result="失败",
                            detail=f"合同编号: {contract_no}, 错误信息: {str(e)}"
                        )
                        
                        QMessageBox.warning(self, '更新失败', f'合同数据不完整或违反完整性约束!\n错误信息: {str(e)}')
                        return
                    except sqlite3.Error as e:
                        conn.rollback()
                        log_error(f"数据库错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="编辑合同",
                            operation_result="失败",
                            detail=f"合同编号: {contract_no}, 错误信息: {str(e)}"
                        )
                        
                        QMessageBox.warning(self, '更新失败', f'数据库操作失败!\n错误信息: {str(e)}')
                        return
                finally:
                    # 关闭数据库连接
                    if cursor:
                        cursor.close()
                    if conn:
                        conn.close()
                    log_debug("数据库连接已关闭")
                
                # 重新加载合同数据
                try:
                    self.loadContracts()
                    log_debug("合同列表已更新")
                except Exception as e:
                    log_error(f"重新加载合同数据失败: {str(e)}")
                
                # 发送数据更新信号
                self.data_updated.emit()
                log_debug("发送数据更新信号")
        except Exception as e:
            log_error(f"编辑合同过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="合同管理",
                operation_content="编辑合同",
                operation_result="异常",
                detail=f"错误信息: {str(e)}"
            )
            
            QMessageBox.critical(self, '系统错误', f'编辑合同失败!\n错误信息: {str(e)}')
    
    def deleteContract(self):
        """
        删除选定的合同
        
        功能: 删除已存在的租赁合同及其相关的租金记录（如果合同未发生过收款行为）,包括验证用户选择、检查收款记录、执行删除操作
        
        实现步骤:
            1. 检查是否选择了要删除的合同
            2. 获取选中合同的合同编号
            3. 检查该合同是否已发生过收款行为
            4. 如果已发生收款行为,则禁止删除并提示用户
            5. 显示确认删除对话框,要求用户二次确认
            6. 执行删除操作（先删除关联的租金记录,再删除合同记录）
            7. 重新加载合同列表,显示最新数据
            8. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、合同不存在、删除失败等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始删除合同")
            
            # 检查是否选择了要删除的合同
            selected_rows = self.contract_table.selectionModel().selectedRows()
            if not selected_rows:
                log_warning("用户未选择要删除的合同")
                QMessageBox.warning(self, '警告', '请先选择要删除的合同!')
                return
            
            row = selected_rows[0].row()
            contract_no = self.contract_table.item(row, 0).text()
            log_debug(f"选择的合同编号: {contract_no}")
            
            # 连接数据库并检查该合同是否已发生收款行为
            from db_utils import DatabaseUtils
            conn = None
            cursor = None
            payment_count = 0
            
            try:
                conn = DatabaseUtils.get_connection()
                if not conn:
                    raise Exception("无法获取数据库连接")
                cursor = conn.cursor()
                
                # 查询该合同的租金记录数量
                try:
                    cursor.execute("SELECT COUNT(*) FROM rent_records WHERE contract_no = ?", (contract_no,))
                    result = cursor.fetchone()
                    payment_count = result[0] if result and result[0] is not None else 0
                    log_debug(f"合同{contract_no}的租金记录数量: {payment_count}")
                except sqlite3.Error as e:
                    log_error(f"查询租金记录失败: {str(e)}")
                    QMessageBox.warning(self, '查询失败', f'检查租金记录时出错!\n错误信息: {str(e)}')
                    return
            except Exception as e:
                log_error(f"数据库连接失败: {str(e)}")
                QMessageBox.warning(self, '连接失败', f'无法连接到数据库!\n错误信息: {str(e)}')
                return
            finally:
                if cursor:
                    cursor.close()
                if conn:
                    conn.close()
                log_debug("数据库连接已关闭")
            
            # 如果有租金记录,不允许删除
            if payment_count > 0:
                log_warning(f"合同{contract_no}已发生收款行为,禁止删除")
                QMessageBox.warning(self, '禁止删除', f'合同编号为:【{contract_no} 】的合同已发生过【 {payment_count} 】次收款,不能删除!')
                return
            
            # 确认删除
            reply = QMessageBox.question(self, '确认删除', f'确定要删除合同编号为{contract_no}的合同吗?\n删除后将无法恢复!',
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                log_debug(f"用户确认删除合同: {contract_no}")
                
                # 连接数据库并删除数据
                try:
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    if not conn:
                        raise Exception("无法获取数据库连接")
                    cursor = conn.cursor()
                    
                    # 开始事务处理
                    conn.execute("BEGIN TRANSACTION")
                    
                    try:
                        # 先删除相关的租金收款记录
                        cursor.execute("DELETE FROM rent_records WHERE contract_no = ?", (contract_no,))
                        log_debug(f"成功删除合同{contract_no}关联的租金记录")
                        
                        # 再删除合同
                        cursor.execute("DELETE FROM contracts WHERE contract_no = ?", (contract_no,))
                        if cursor.rowcount == 0:
                            conn.rollback()
                            log_error(f"合同{contract_no}不存在,删除失败")
                            QMessageBox.warning(self, '删除失败', '找不到该合同,可能已被删除!')
                            return
                        log_debug(f"成功删除合同{contract_no}")
                        
                        # 提交事务
                        conn.commit()
                        log_info(f"成功删除合同{contract_no}")
                        
                        # 记录操作日志 - 操作成功
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="删除合同",
                            operation_result="成功",
                            detail=f"合同编号: {contract_no}"
                        )
                        
                        # 显示成功消息
                        QMessageBox.information(self, '删除成功', f'合同编号为【{contract_no}】的合同已成功删除!')
                    except sqlite3.Error as e:
                        conn.rollback()
                        log_error(f"删除数据失败: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="合同管理",
                            operation_content="删除合同",
                            operation_result="失败",
                            detail=f"合同编号: {contract_no}, 错误信息: {str(e)}"
                        )
                        
                        QMessageBox.warning(self, '删除失败', f'删除数据时出错!\n错误信息: {str(e)}')
                        return
                except Exception as e:
                    if conn:
                        conn.rollback()
                    log_error(f"数据库操作失败: {str(e)}")
                    QMessageBox.warning(self, '操作失败', f'数据库操作失败!\n错误信息: {str(e)}')
                    return
                finally:
                    # 关闭数据库连接
                    if cursor:
                        cursor.close()
                    if conn:
                        conn.close()
                    log_debug("数据库连接已关闭")
                
                # 重新加载合同数据
                try:
                    self.loadContracts()
                    log_debug("合同列表已更新")
                except Exception as e:
                    log_error(f"重新加载合同数据失败: {str(e)}")
                
                # 发送数据更新信号
                self.data_updated.emit()
                log_debug("发送数据更新信号")
        except Exception as e:
            log_error(f"删除合同过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="合同管理",
                operation_content="删除合同",
                operation_result="异常",
                detail=f"错误信息: {str(e)}"
            )
            
            QMessageBox.critical(self, '系统错误', f'删除合同失败!\n错误信息: {str(e)}')
    
    def exportContracts(self):
        # 导出合同数据
        # 如果表格为空,提示用户
        if self.contract_table.rowCount() == 0:
            QMessageBox.warning(self, '警告', '当前没有可导出的数据,请先查询或加载合同记录!')
            return
        
        # 创建导出数据对话框
        dialog = ExportDataDialog(self)
        if dialog.exec_():
            # 获取选择的导出格式
            export_format = dialog.getExportFormat()
            
            # 创建导出文件目录
            export_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '导出文件')
            if not os.path.exists(export_dir):
                os.makedirs(export_dir)
            
            # 从表格中获取当前显示的记录数据
            headers = []
            data = []
            
            # 获取表头
            for col_idx in range(self.contract_table.columnCount()):
                headers.append(self.contract_table.horizontalHeaderItem(col_idx).text())
            
            # 获取表格内容
            for row_idx in range(self.contract_table.rowCount()):
                # 跳过隐藏的行
                if self.contract_table.isRowHidden(row_idx):
                    continue
                
                row_data = []
                for col_idx in range(self.contract_table.columnCount()):
                    item = self.contract_table.item(row_idx, col_idx)
                    row_data.append(item.text() if item else '')
                data.append(row_data)
            
  
            # today = date.today().strftime('%Y%m%d_%H%M%S')
            today = datetime.now().strftime("%Y%m%d_%H%M%S")
            try:
                if export_format == 'Excel':
                    # Excel格式导出
                    file_path = os.path.join(export_dir, f'合同数据_{today}.xlsx')
                    self.exportToExcel(headers, data, file_path)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'合同数据已成功导出到\n{file_path},并已自动打开文件')
                else:
                    # PDF格式导出
                    file_path = os.path.join(export_dir, f'合同数据_{today}.pdf')
                    self.exportToPDF(headers, data, file_path)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'合同数据已成功导出到\n{file_path},并已自动打开文件')
            except Exception as e:
                QMessageBox.critical(self, '导出失败', f'导出合同数据时发生错误:\n{str(e)}')
    
    def exportToExcel(self, headers, data, file_path):
        """导出数据到Excel并优化表格样式"""
        # 导入必要的样式类
        from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
        from openpyxl.utils import get_column_letter
        # 创建DataFrame
        df = pd.DataFrame(data, columns=headers)
        
        # 创建ExcelWriter对象
        with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
            # 将数据写入Excel
            df.to_excel(writer, index=False, sheet_name='合同数据')
            
            # 获取工作表
            worksheet = writer.sheets['合同数据']
            
            # 设置列宽自适应
            for col_idx, col in enumerate(worksheet.columns):
                max_length = 0
                column = col_idx + 1  # 列索引从1开始
                
                # 计算每列的最大宽度
                for cell in col:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                
                # 设置列宽（加一点边距）
                adjusted_width = (max_length + 2) * 1.2
                worksheet.column_dimensions[get_column_letter(column)].width = adjusted_width
            
            # 设置表头样式
            header_font = Font(bold=True, color="FFFFFF")
            header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
            border_style = Border(left=Side(style='thin'), 
                                 right=Side(style='thin'), 
                                 top=Side(style='thin'), 
                                 bottom=Side(style='thin'))
            
            # 应用表头样式
            for cell in worksheet[1]:
                cell.font = header_font
                cell.fill = header_fill
                cell.alignment = Alignment(horizontal="center", vertical="center")
                cell.border = border_style
            
            # 设置数据区域样式
            for row in worksheet.iter_rows(min_row=2, max_row=worksheet.max_row):
                for cell in row:
                    cell.alignment = Alignment(horizontal="center", vertical="center")
                    cell.border = border_style
    
    def exportToPDF(self, headers, data, file_path):
        """导出数据到PDF并优化页面样式"""
        from reportlab.pdfbase import pdfmetrics
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.lib.units import inch
        from reportlab.lib.pagesizes import landscape
        from reportlab.lib.pagesizes import letter
        from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
        from reportlab.lib import colors
        from reportlab.lib.styles import getSampleStyleSheet
        
        # 尝试注册多个中文字体,增加成功概率
        font_name = 'Helvetica'
        font_registered = False
        
        # Windows系统常用的中文字体列表
        chinese_fonts = [
            ('SimHei', 'simhei.ttf'),
            ('Microsoft YaHei', 'msyh.ttc'),
            ('Arial Unicode MS', 'arialuni.ttf'),
            ('FangSong', 'simsunb.ttf'),
            ('KaiTi', 'simkai.ttf')
        ]
        
        # 尝试从系统字体目录加载字体
        system_font_paths = [
            'C:/Windows/Fonts/',
            'C:/WINNT/Fonts/',
            os.path.expanduser('~/.fonts/')
        ]
        
        # 尝试注册字体
        for font_family, font_file in chinese_fonts:
            try:
                # 首先尝试直接注册（假设字体在系统路径中）
                pdfmetrics.registerFont(TTFont(font_family, font_file))
                font_name = font_family
                font_registered = True
                break
            except:
                # 尝试从系统字体目录注册
                for font_path in system_font_paths:
                    try:
                        full_font_path = os.path.join(font_path, font_file)
                        if os.path.exists(full_font_path):
                            pdfmetrics.registerFont(TTFont(font_family, full_font_path))
                            font_name = font_family
                            font_registered = True
                            break
                    except:
                        continue
                if font_registered:
                    break
        
        # 准备表格数据并处理长文本
        table_data = [headers] + []
        for row in data:
            new_row = []
            for cell in row:
                # 处理单元格内容,确保能正确显示
                if isinstance(cell, str):
                    # 对于长文本,可以考虑添加换行符或缩短显示
                    new_row.append(cell)
                else:
                    new_row.append(str(cell) if cell is not None else '')
            table_data.append(new_row)
        
        # 计算内容所需的最小宽度,以决定是否需要横向排版
        # 估算每列内容的最大宽度（以字符数为基础）
        column_widths = [0] * len(headers)
        for row in table_data:
            for i, cell in enumerate(row):
                # 假设每个中文字符宽度约为10,英文字符约为5
                char_count = len(cell)
                # 中文字符比例估算
                chinese_chars = sum(1 for c in cell if '\u4e00' <= c <= '\u9fff')
                # 估算列宽需求（像素）
                estimated_width = chinese_chars * 10 + (char_count - chinese_chars) * 5
                column_widths[i] = max(column_widths[i], estimated_width)
        
        # 计算总宽度需求（加上列间距）
        total_width_needed = sum(column_widths) + (len(headers) - 1) * 5
        
        # 设置页面大小和方向
        # 默认使用竖向页面
        pagesize = letter
        page_width = letter[0] - 72  # 减去左右边距
        
        # 如果内容宽度超过页面宽度,切换为横向排版
        if total_width_needed > page_width:
            pagesize = landscape(letter)
            page_width = letter[1] - 72  # 横向时宽度变为原高度减去边距
        
        # 创建文档,减小页边距以增加内容区域
        doc = SimpleDocTemplate(file_path, pagesize=pagesize,
                               rightMargin=36, leftMargin=36,
                               topMargin=36, bottomMargin=36)
        elements = []
        
        # 添加标题
        styles = getSampleStyleSheet()
        # 如果注册了中文字体,更新标题样式
        if font_registered:
            styles['Title'].fontName = font_name
            styles['Normal'].fontName = font_name
        
        title = Paragraph("合同数据报表", styles['Title'])
        elements.append(title)
        elements.append(Spacer(1, 12))
        
        # 添加报表生成日期
        today = date.today().strftime("%Y%m%d_%H%M%S")
        date_text = Paragraph(f"报表生成日期:{today}", styles['Normal'])
        elements.append(date_text)
        elements.append(Spacer(1, 24))
        
        # 计算页面宽度和表格宽度
        current_page_width = pagesize[0] - doc.leftMargin - doc.rightMargin
        table_width = current_page_width
        
        # 动态计算每列的宽度,根据列的数量平均分配
        col_widths = [table_width / len(headers) for _ in headers]
        
        # 创建表格,指定列宽
        table = Table(table_data, colWidths=col_widths)
        
        # 设置表格样式
        table_style = TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#4F81BD')),  # 深蓝色表头背景
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # 白色表头文字
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 居中对齐
            ('FONTNAME', (0, 0), (-1, 0), font_name),  # 表头字体
            ('FONTSIZE', (0, 0), (-1, -1), 10),  # 设置字体大小,确保内容能显示
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),  # 表头下内边距
            ('TOPPADDING', (0, 0), (-1, 0), 12),  # 表头上内边距
            ('GRID', (0, 0), (-1, -1), 1, colors.black),  # 表格边框
            ('FONTNAME', (0, 1), (-1, -1), font_name),  # 数据字体
            ('BACKGROUND', (0, 1), (-1, -1), colors.white),  # 数据行背景色
            ('BACKGROUND', (0, 2), (-1, -1), colors.HexColor('#F2F2F2')),  # 交替行背景色
            ('WORDWRAP', (0, 0), (-1, -1), 1),  # 启用自动换行
        ])
        table.setStyle(table_style)
        
        # 添加表格到元素列表
        elements.append(table)
        
        # 添加页脚信息
        elements.append(Spacer(1, 24))
        footer_text = Paragraph("租赁合同管理系统 - 合同数据报表", styles['Normal'])
        footer_text.alignment = 1  # 居中对齐
        elements.append(footer_text)
        
        # 构建PDF
        doc.build(elements)
    
    def importContractsFromExcel(self):
        # 从Excel导入合同资料
        # 选择Excel文件
        file_path, _ = QFileDialog.getOpenFileName(self, '选择文件', '', 'Excel Files (*.xlsx)')
        if not file_path:
            return
        
        try:
            # 获取当前登录用户
            current_user_id = auth_manager.current_user_id
            current_user = auth_manager.current_user
            
            # 读取Excel文件
            df = pd.read_excel(file_path)
            
            # 验证Excel格式是否正确（检查是否包含必要的列）
            required_columns = ['合同编号', '签约日期', '房屋编号', '房屋位置', '房屋面积', '出租方', '承租方', '承租人', '承租人身份证', '承租人电话', '租赁开始日期', '租赁截止日期', '合同状态', '付款方式', '月租金额', '总租金', '年租金', '押金', '用途', '水电费计算方式']
            missing_columns = [col for col in required_columns if col not in df.columns]
            
            if missing_columns:
                missing_text = ', '.join(missing_columns)
                required_text = ', '.join(required_columns)
                message = f'Excel文件缺少必要的列:{missing_text}\n请确保Excel文件包含以下列:{required_text}'
                QMessageBox.warning(self, '格式错误', message)
                
                # 记录操作日志 - 格式错误
                record_operation(
                    self.auth_manager.current_user_id,
                    self.auth_manager.current_user,
                    "合同管理",
                    "导入合同",
                    "失败",
                    f"文件路径: {file_path}, 错误: 缺少必要列 {missing_text}"
                )
                return
            
            # 开始导入数据
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            success_count = 0
            failed_count = 0
            failed_records = []
            
            for idx, row in df.iterrows():
                try:
                    # 提取数据
                    contract_no = str(row['合同编号']).strip() if pd.notna(row['合同编号']) else ''
                    sign_date = str(row['签约日期']).strip() if pd.notna(row['签约日期']) else ''
                    house_no = str(row['房屋编号']).strip() if pd.notna(row['房屋编号']) else ''
                    house_location = str(row['房屋位置']).strip() if pd.notna(row['房屋位置']) else ''
                    
                    # 处理房屋面积
                    try:
                        # 移除千位分隔符再转换为浮点数
                        house_area_str = str(row['房屋面积']).strip().replace(',', '') if pd.notna(row['房屋面积']) else '0'
                        house_area = float(house_area_str)
                    except ValueError:
                        house_area = 0.0
                    
                    lessor = str(row['出租方']).strip() if pd.notna(row['出租方']) else ''
                    legal_representative = str(row['法定代表人']).strip() if '法定代表人' in df.columns and pd.notna(row['法定代表人']) else ''
                    person_in_charge = str(row['分管负责人']).strip() if '分管负责人' in df.columns and pd.notna(row['分管负责人']) else ''
                    contact_phone = str(row['联系电话']).strip() if '联系电话' in df.columns and pd.notna(row['联系电话']) else ''
                    lessee = str(row['承租方']).strip() if pd.notna(row['承租方']) else ''
                    tenant = str(row['承租人']).strip() if pd.notna(row['承租人']) else ''
                    tenant_id = str(row['承租人身份证']).strip() if pd.notna(row['承租人身份证']) else ''
                    tenant_phone = str(row['承租人电话']).strip() if pd.notna(row['承租人电话']) else ''
                    start_date = str(row['租赁开始日期']).strip() if pd.notna(row['租赁开始日期']) else ''
                    end_date = str(row['租赁截止日期']).strip() if pd.notna(row['租赁截止日期']) else ''
                    status = str(row['合同状态']).strip() if pd.notna(row['合同状态']) else ''
                    payment_method = str(row['付款方式']).strip() if pd.notna(row['付款方式']) else ''
                    
                    # 处理金额字段
                    try:
                        # 移除千位分隔符再转换为浮点数
                        monthly_rent_str = str(row['月租金额']).strip().replace(',', '') if pd.notna(row['月租金额']) else '0'
                        monthly_rent = float(monthly_rent_str)
                    except ValueError:
                        monthly_rent = 0.0
                    
                    try:
                        # 移除千位分隔符再转换为浮点数
                        total_rent_str = str(row['总租金']).strip().replace(',', '') if pd.notna(row['总租金']) else '0'
                        total_rent = float(total_rent_str)
                    except ValueError:
                        total_rent = 0.0
                    
                    try:
                        # 移除千位分隔符再转换为浮点数
                        annual_rent_str = str(row['年租金']).strip().replace(',', '') if pd.notna(row['年租金']) else '0'
                        annual_rent = float(annual_rent_str)
                    except ValueError:
                        annual_rent = 0.0
                    
                    try:
                        # 移除千位分隔符再转换为浮点数
                        deposit_str = str(row['押金']).strip().replace(',', '') if pd.notna(row['押金']) else '0'
                        deposit = float(deposit_str)
                    except ValueError:
                        deposit = 0.0
                    
                    try:
                        # 移除千位分隔符再转换为浮点数
                        water_fee_str = str(row['水费']).strip().replace(',', '') if '水费' in df.columns and pd.notna(row['水费']) else '0'
                        water_fee = float(water_fee_str)
                    except ValueError:
                        water_fee = 0.0
                    
                    try:
                        # 移除千位分隔符再转换为浮点数
                        electricity_fee_str = str(row['电费']).strip().replace(',', '') if '电费' in df.columns and pd.notna(row['电费']) else '0'
                        electricity_fee = float(electricity_fee_str)
                    except ValueError:
                        electricity_fee = 0.0
                    
                    usage = str(row['用途']).strip() if pd.notna(row['用途']) else ''
                    utility_method = str(row['水电费计算方式']).strip() if pd.notna(row['水电费计算方式']) else ''
                    remarks = str(row['备注']).strip() if '备注' in df.columns and pd.notna(row['备注']) else ''
                    
                    # 验证必填字段
                    if not contract_no or not sign_date or not house_no or not house_location or not lessor or not lessee or not tenant or not tenant_id or not tenant_phone or not start_date or not end_date or not status or not payment_method:
                        failed_count += 1
                        failed_records.append(f'第{idx+1}行:必填字段不完整')
                        continue
                    
                    # 计算签约年月
                    try:
                        sign_date_obj = datetime.strptime(sign_date, '%Y-%m-%d')
                        sign_year_month = f"{sign_date_obj.year}-{sign_date_obj.month:02d}"
                    except ValueError:
                        failed_count += 1
                        failed_records.append(f'第{idx+1}行:签约日期格式不正确,应为YYYY-MM-DD')
                        continue
                    
                    # 检查合同编号是否已存在
                    cursor.execute("SELECT id FROM contracts WHERE contract_no = ?", (contract_no,))
                    if cursor.fetchone():
                        # 如果合同已存在,则更新
                        cursor.execute(
                            """UPDATE contracts SET 
                                sign_date = ?, sign_year_month = ?, house_no = ?, house_location = ?, house_area = ?, 
                                lessor = ?, legal_representative = ?, person_in_charge = ?, contact_phone = ?, 
                                lessee = ?, tenant = ?, tenant_id = ?, tenant_phone = ?, start_date = ?, end_date = ?, 
                                status = ?, payment_method = ?, monthly_rent = ?, total_rent = ?, annual_rent = ?, 
                                deposit = ?, usage = ?, utility_method = ?, water_fee = ?, electricity_fee = ?, remarks = ? 
                            WHERE contract_no = ?""",
                            (sign_date, sign_year_month, house_no, house_location, house_area, 
                             lessor, legal_representative, person_in_charge, contact_phone, 
                             lessee, tenant, tenant_id, tenant_phone, start_date, end_date, 
                             status, payment_method, monthly_rent, total_rent, annual_rent, 
                             deposit, usage, utility_method, water_fee, electricity_fee, remarks, contract_no)
                        )
                    else:
                        # 插入新合同
                        cursor.execute(
                            """INSERT INTO contracts (
                                contract_no, sign_date, sign_year_month, house_no, house_location, house_area, 
                                lessor, legal_representative, person_in_charge, contact_phone, 
                                lessee, tenant, tenant_id, tenant_phone, start_date, end_date, 
                                status, payment_method, monthly_rent, total_rent, annual_rent, 
                                deposit, usage, utility_method, water_fee, electricity_fee, remarks 
                            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                            (contract_no, sign_date, sign_year_month, house_no, house_location, house_area, 
                             lessor, legal_representative, person_in_charge, contact_phone, 
                             lessee, tenant, tenant_id, tenant_phone, start_date, end_date, 
                             status, payment_method, monthly_rent, total_rent, annual_rent, 
                             deposit, usage, utility_method, water_fee, electricity_fee, remarks)
                        )
                    
                    success_count += 1
                    
                except Exception as e:
                    failed_count += 1
                    failed_records.append(f'第{idx+1}行:{str(e)}')
            
            # 提交更改
            conn.commit()
            
            # 刷新表格
            self.loadContracts(conn)
            
            # 关闭连接
            conn.close()
            
            # 显示导入结果
            result_msg = f'导入完成!\n成功导入:{success_count}条记录\n导入失败:{failed_count}条记录'
            
            # 记录操作日志 - 导入结果
            record_operation(
                self.auth_manager.current_user_id,
                self.auth_manager.current_user,
                "合同管理",
                "导入合同",
                "成功" if failed_count == 0 else "部分成功",
                f"文件路径: {file_path}, 成功: {success_count}条, 失败: {failed_count}条"
            )
            
            if failed_count > 0:
                detailed_msg = result_msg + '\n\n失败详情:\n' + '\n'.join(failed_records[:10])  # 只显示前10条失败记录
                if len(failed_records) > 10:
                    detailed_msg += f'\n... 还有{len(failed_records)-10}条失败记录'
                QMessageBox.warning(self, '导入结果', detailed_msg)
            else:
                QMessageBox.information(self, '导入成功', result_msg)
                
        except Exception as e:
            # 获取当前登录用户
            current_user_id = auth_manager.current_user_id
            current_user = auth_manager.current_user
            
            # 记录操作日志 - 导入异常
            record_operation(
                self.auth_manager.current_user_id,
                self.auth_manager.current_user,
                "合同管理",
                "导入合同",
                "异常",
                f"文件路径: {file_path}, 错误信息: {str(e)}"
            )
            
            QMessageBox.critical(self, '导入失败', f'导入合同资料时发生错误:\n{str(e)}')
        
    def exportToPDF(self, headers, data, file_path):
        """导出数据到PDF并优化页面样式"""
        from reportlab.pdfbase import pdfmetrics
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.lib.units import inch
        from reportlab.lib.pagesizes import landscape, letter
        from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
        from reportlab.lib.styles import getSampleStyleSheet
        from reportlab.lib import colors
        import sys
        
        # 尝试注册多个中文字体,增加成功概率
        font_name = 'Helvetica'
        font_registered = False
        
        # Windows系统常用的中文字体列表
        chinese_fonts = [
            ('SimHei', 'simhei.ttf'),
            ('Microsoft YaHei', 'msyh.ttc'),
            ('Arial Unicode MS', 'arialuni.ttf'),
            ('FangSong', 'simsunb.ttf'),
            ('KaiTi', 'simkai.ttf')
        ]
        
        # 尝试从系统字体目录加载字体
        system_font_paths = [
            'C:/Windows/Fonts/',
            'C:/WINNT/Fonts/',
            os.path.expanduser('~/.fonts/')
        ]
        
        # 尝试注册字体
        for font_family, font_file in chinese_fonts:
            try:
                # 首先尝试直接注册（假设字体在系统路径中）
                pdfmetrics.registerFont(TTFont(font_family, font_file))
                font_name = font_family
                font_registered = True
                break
            except:
                # 尝试从系统字体目录注册
                for font_path in system_font_paths:
                    try:
                        full_font_path = os.path.join(font_path, font_file)
                        if os.path.exists(full_font_path):
                            pdfmetrics.registerFont(TTFont(font_family, full_font_path))
                            font_name = font_family
                            font_registered = True
                            break
                    except:
                        continue
                if font_registered:
                    break
        
        # 准备表格数据并处理长文本
        table_data = [headers] + []
        for row in data:
            new_row = []
            for cell in row:
                # 处理单元格内容,确保能正确显示
                if isinstance(cell, str):
                    # 对于长文本,可以考虑添加换行符或缩短显示
                    new_row.append(cell)
                else:
                    new_row.append(str(cell) if cell is not None else '')
            table_data.append(new_row)
        
        # 计算内容所需的最小宽度,以决定是否需要横向排版
        # 估算每列内容的最大宽度（以字符数为基础）
        column_widths = [0] * len(headers)
        for row in table_data:
            for i, cell in enumerate(row):
                # 假设每个中文字符宽度约为10,英文字符约为5
                char_count = len(cell)
                # 中文字符比例估算
                chinese_chars = sum(1 for c in cell if '\u4e00' <= c <= '\u9fff')
                # 估算列宽需求（像素）
                estimated_width = chinese_chars * 10 + (char_count - chinese_chars) * 5
                column_widths[i] = max(column_widths[i], estimated_width)
        
        # 计算总宽度需求（加上列间距）
        total_width_needed = sum(column_widths) + (len(headers) - 1) * 5
        
        # 设置页面大小和方向
        # 默认使用竖向页面
        pagesize = letter
        page_width = letter[0] - 72  # 减去左右边距
        
        # 如果内容宽度超过页面宽度,切换为横向排版
        if total_width_needed > page_width:
            pagesize = landscape(letter)
            page_width = letter[1] - 72  # 横向时宽度变为原高度减去边距
        
        # 创建文档,减小页边距以增加内容区域
        doc = SimpleDocTemplate(file_path, pagesize=pagesize,
                               rightMargin=36, leftMargin=36,
                               topMargin=36, bottomMargin=36)
        elements = []
        
        # 添加标题
        styles = getSampleStyleSheet()
        # 如果注册了中文字体,更新标题样式
        if font_registered:
            styles['Title'].fontName = font_name
            styles['Normal'].fontName = font_name
        
        title = Paragraph("合同数据报表", styles['Title'])
        elements.append(title)
        elements.append(Spacer(1, 12))
        
        # 添加报表生成日期
        today_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        date_text = Paragraph(f"报表生成日期:{today_str}", styles['Normal'])
        elements.append(date_text)
        elements.append(Spacer(1, 24))
        
        # 计算页面宽度和表格宽度
        current_page_width = pagesize[0] - doc.leftMargin - doc.rightMargin
        table_width = current_page_width
        
        # 动态计算每列的宽度,根据列的数量平均分配
        col_widths = [table_width / len(headers) for _ in headers]
        
        # 创建表格,指定列宽
        table = Table(table_data, colWidths=col_widths)
        
        # 设置表格样式
        table_style = TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#4F81BD')),  # 深蓝色表头背景
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # 白色表头文字
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 居中对齐
            ('FONTNAME', (0, 0), (-1, 0), font_name),  # 表头字体
            ('FONTSIZE', (0, 0), (-1, -1), 10),  # 设置字体大小,确保内容能显示
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),  # 表头下内边距
            ('TOPPADDING', (0, 0), (-1, 0), 12),  # 表头上内边距
            ('GRID', (0, 0), (-1, -1), 1, colors.black),  # 表格边框
            ('FONTNAME', (0, 1), (-1, -1), font_name),  # 数据字体
            ('BACKGROUND', (0, 1), (-1, -1), colors.white),  # 数据行背景色
            ('BACKGROUND', (0, 2), (-1, -1), colors.HexColor('#F2F2F2')),  # 交替行背景色
            ('WORDWRAP', (0, 0), (-1, -1), 1),  # 启用自动换行
        ])
        table.setStyle(table_style)
        
        # 添加表格到元素列表
        elements.append(table)
        
        # 添加页脚信息
        elements.append(Spacer(1, 24))
        footer_text = Paragraph("租赁合同管理系统 - 合同数据报表", styles['Normal'])
        footer_text.alignment = 1  # 居中对齐
        elements.append(footer_text)
        
        # 构建PDF
        doc.build(elements)

# 合同对话框
class ContractDialog(QDialog):
    def __init__(self, is_edit=False, contract_data=None):
        super().__init__()
        self.is_edit = is_edit
        self.contract_data = contract_data
        # 初始化认证管理器
        from user_auth import auth_manager
        self.auth_manager = auth_manager
        # 初始化调整大小相关属性
        self.last_resize_time = None
        self.resize_timer = QTimer(self)
        self.resize_timer.timeout.connect(self._adjust_column_widths_on_resize)
        self.initUI()
    
    def generateContractNo(self):
        # 生成合同编号:HT+4位年份+3位序号
        try:
            # 获取当前年份
            current_year = str(date.today().year)
            
            # 连接数据库
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                log_error("无法获取数据库连接")
                QMessageBox.warning(dialog, '连接失败', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 查询当前年份的最大序号
            cursor.execute("SELECT MAX(contract_no) FROM contracts WHERE contract_no LIKE ?", (f"HT{current_year}%",))
            max_contract_no = cursor.fetchone()[0]
            
            conn.close()
            
            # 计算新序号
            if max_contract_no:
                # 提取序号部分并加1
                seq = int(max_contract_no[6:]) + 1
            else:
                # 如果当前年份没有合同,序号从1开始
                seq = 1
            
            # 生成新合同编号
            contract_no = f"HT{current_year}{seq:03d}"
            return contract_no
        except Exception as e:
            # 发生错误时返回默认值
            return f"HT{current_year}001"
    
    def initUI(self):
        # 设置窗口标题
        if self.is_edit:
            self.setWindowTitle('编辑合同')
        else:
            self.setWindowTitle('添加合同')
        
        # 设置窗口大小 - 优化为更合适的尺寸
        self.resize(765, 790)  # 设置为合适的窗口尺寸（宽度增加5px，高度增加10像素）
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建滚动区域
        scroll_widget = QWidget()
        scroll_layout = QVBoxLayout(scroll_widget)
        scroll_widget.setLayout(scroll_layout)
        
        # 创建滚动条区域
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setWidget(scroll_widget)
        
        # 将滚动区域添加到主布局
        main_layout.addWidget(scroll_area)
        
        # 创建表单布局
        form_layout = QFormLayout()
        
        # 创建水平布局来放置签约日期、合同编号和合同状态
        self.date_and_no_layout = QHBoxLayout()
        
        # 签约日期
        self.sign_date_edit = QDateEdit()
        self.sign_date_edit.setCalendarPopup(True)
        self.sign_date_edit.setDate(QDate.currentDate())
        sign_date_label = QLabel('签约日期:')
        # 使用全局样式
        self.date_and_no_layout.addWidget(sign_date_label)
        self.date_and_no_layout.addWidget(self.sign_date_edit)
        
        # 添加一个间隔
        self.date_and_no_layout.addStretch()
        
        # 合同编号
        self.contract_no_edit = QLineEdit()
        # 如果是添加合同模式,自动生成合同编号
        if not self.is_edit:
            contract_no = self.generateContractNo()
            self.contract_no_edit.setText(contract_no)
            # 禁用合同编号编辑
            self.contract_no_edit.setReadOnly(True)
        contract_no_label = QLabel('合同编号:')
        # 使用全局样式
        self.date_and_no_layout.addWidget(contract_no_label)
        self.date_and_no_layout.addWidget(self.contract_no_edit)
        
        # 添加收款情况标签
        self.payment_status_label = QLabel('收款情况:')
        # 使用全局样式
        # 初始化为文本框而不是标签,并设置默认值为"未结清"
        self.payment_status_value_label = QLineEdit('未结清')
        # 设置字体颜色为红色,边框线加粗且为红色,文本加粗
        self.payment_status_value_label.setStyleSheet('color: red; border: 2px solid red; font-weight: bold;')
        # 设置文本水平居中对齐（使用Qt API更可靠）
        self.payment_status_value_label.setAlignment(Qt.AlignCenter)
        # 设置固定宽度
        self.payment_status_value_label.setFixedWidth(80)
        # 设置为只读,防止用户编辑
        self.payment_status_value_label.setReadOnly(True)
        self.date_and_no_layout.addWidget(self.payment_status_label)
        self.date_and_no_layout.addWidget(self.payment_status_value_label)
        
        # 添加一个间隔
        self.date_and_no_layout.addStretch()
        
        # 合同状态 - 设置为只读
        self.status_edit = QComboBox()
        self.status_edit.addItems(['执行中', '已完成', '已逾期'])
        # 设置为禁用状态（只读）
        self.status_edit.setEnabled(False)
        # 添加样式使只读状态更明显
        self.status_edit.setStyleSheet('background-color: #f0f0f0; color: #666;')
        status_label = QLabel('合同状态:')
        # 使用全局样式
        self.date_and_no_layout.addWidget(status_label)
        self.date_and_no_layout.addWidget(self.status_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(self.date_and_no_layout)
        
        # 房屋编号、面积和作用布局
        house_info_layout = QHBoxLayout()
        
        # 房屋编号
        house_layout = QHBoxLayout()
        self.house_no_edit = QLineEdit()
        select_house_button = QPushButton('...')
        select_house_button.setFixedWidth(30)
        select_house_button.clicked.connect(self.showHouseSelectionDialog)
        house_layout.addWidget(self.house_no_edit)
        house_layout.addWidget(select_house_button)
        house_no_label = QLabel('房屋编号:')
        # 使用全局样式
        house_info_layout.addWidget(house_no_label)
        house_info_layout.addLayout(house_layout)
        
        # 房屋类型
        self.house_type_edit = QLineEdit()
        self.house_type_edit.setReadOnly(True)  # 设置为只读
        house_type_label = QLabel('房屋类型:')
        # 使用全局样式
        house_info_layout.addWidget(house_type_label)
        house_info_layout.addWidget(self.house_type_edit)
        
        # 添加一个间隔
        house_info_layout.addStretch()
        
        # 房屋面积
        self.house_area_edit = QDoubleSpinBox()
        self.house_area_edit.setRange(0.0, 999999.99)
        self.house_area_edit.setDecimals(2)
        self.house_area_edit.setValue(0.00)
        house_area_label = QLabel('房屋面积(平方米):')
        # 使用全局样式
        house_info_layout.addWidget(house_area_label)
        house_info_layout.addWidget(self.house_area_edit)
        
        # 添加一个间隔
        house_info_layout.addStretch()
        
        # 作用
        self.purpose_edit = QComboBox()
        self.purpose_edit.addItems(['商用', '住宅'])
        purpose_label = QLabel('作用:')
        # 使用全局样式
        house_info_layout.addWidget(purpose_label)
        house_info_layout.addWidget(self.purpose_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(house_info_layout)
        
        # 房屋位置
        self.house_location_edit = QLineEdit()
        house_location_label = QLabel('房屋位置:')
        # 使用全局样式
        form_layout.addRow(house_location_label, self.house_location_edit)
        
        # 出租方（甲方）
        landlord_layout = QHBoxLayout()
        self.lessor_edit = QLineEdit()
        select_landlord_button = QPushButton('...')
        select_landlord_button.setFixedWidth(30)
        select_landlord_button.clicked.connect(self.showLandlordSelectionDialog)
        landlord_layout.addWidget(self.lessor_edit)
        landlord_layout.addWidget(select_landlord_button)
        lessor_label = QLabel('出租方（甲方）:')
        # 使用全局样式
        form_layout.addRow(lessor_label, landlord_layout)
        
        # 法定代表人、分管负责人和联系电话布局
        representative_layout = QHBoxLayout()
        
        # 法定代表人
        self.legal_representative_edit = QLineEdit()
        legal_representative_label = QLabel('法定代表人:')
        # 使用全局样式
        representative_layout.addWidget(legal_representative_label)
        representative_layout.addWidget(self.legal_representative_edit)
        
        # 添加一个间隔
        representative_layout.addStretch()
        
        # 分管负责人
        self.person_in_charge_edit = QLineEdit()
        person_in_charge_label = QLabel('分管负责人:')
        # 使用全局样式
        representative_layout.addWidget(person_in_charge_label)
        representative_layout.addWidget(self.person_in_charge_edit)
        
        # 添加一个间隔
        representative_layout.addStretch()
        
        # 联系电话
        self.contact_phone_edit = QLineEdit()
        contact_phone_label = QLabel('联系电话:')
        # 使用全局样式
        representative_layout.addWidget(contact_phone_label)
        representative_layout.addWidget(self.contact_phone_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(representative_layout)
        
        # 添加实体分隔线
        separator2 = QFrame()
        separator2.setFrameShape(QFrame.HLine)
        separator2.setFrameShadow(QFrame.Sunken)
        form_layout.addRow(separator2)
        
        # 承租方（乙方）
        tenant_layout = QHBoxLayout()
        self.lessee_edit = QLineEdit()
        select_tenant_button = QPushButton('...')
        select_tenant_button.setFixedWidth(30)
        select_tenant_button.clicked.connect(self.showTenantSelectionDialog)
        tenant_layout.addWidget(self.lessee_edit)
        tenant_layout.addWidget(select_tenant_button)
        lessee_label = QLabel('承租方（乙方）:')
        # 使用全局样式
        form_layout.addRow(lessee_label, tenant_layout)
        
        # 承租人、承租人身份证和承租人电话布局
        tenant_info_layout = QHBoxLayout()
        
        # 承租人
        self.tenant_edit = QLineEdit()
        tenant_label = QLabel('承租人:')
        # 使用全局样式
        tenant_info_layout.addWidget(tenant_label)
        tenant_info_layout.addWidget(self.tenant_edit)
        
        # 添加一个间隔
        tenant_info_layout.addStretch()
        
        # 承租人身份证
        self.tenant_id_edit = QLineEdit()
        tenant_id_label = QLabel('承租人身份证:')
        # 使用全局样式
        tenant_info_layout.addWidget(tenant_id_label)
        tenant_info_layout.addWidget(self.tenant_id_edit)
        
        # 添加一个间隔
        tenant_info_layout.addStretch()
        
        # 承租人电话
        self.tenant_phone_edit = QLineEdit()
        tenant_phone_label = QLabel('承租人电话:')
        # 使用全局样式
        tenant_info_layout.addWidget(tenant_phone_label)
        tenant_info_layout.addWidget(self.tenant_phone_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(tenant_info_layout)
        
        # 添加实体分隔线
        separator3 = QFrame()
        separator3.setFrameShape(QFrame.HLine)
        separator3.setFrameShadow(QFrame.Sunken)
        form_layout.addRow(separator3)
        
        # 租赁开始日期和截止日期布局
        lease_date_layout = QHBoxLayout()
        
        # 租赁开始日期 - 确保标题与输入框间隔距离为2
        start_date_sub_layout = QHBoxLayout()
        self.start_date_edit = QDateEdit()
        self.start_date_edit.setCalendarPopup(True)
        self.start_date_edit.setDate(QDate.currentDate())
        start_date_label = QLabel('租赁开始日期:')
        start_date_sub_layout.addWidget(start_date_label)
        start_date_sub_layout.setSpacing(2)  # 设置组件间隔为2
        start_date_sub_layout.addWidget(self.start_date_edit)
        lease_date_layout.addLayout(start_date_sub_layout)
        
        # 添加合同期下拉框
        self.contract_period_combo = QComboBox()
        self.contract_period_combo.addItems(['1', '2', '3'])
        self.contract_period_combo.setCurrentText('1')
        contract_period_label = QLabel('合同期:')
        year_label = QLabel('年期')
        lease_date_layout.addWidget(contract_period_label)
        lease_date_layout.addWidget(self.contract_period_combo)
        lease_date_layout.addWidget(year_label)
        
        # 添加一个间隔
        lease_date_layout.addStretch()
        
        # 租赁截止日期 - 确保标题与输入框间隔距离为2
        end_date_sub_layout = QHBoxLayout()
        self.end_date_edit = QDateEdit()
        self.end_date_edit.setCalendarPopup(True)
        self.end_date_edit.setDate(QDate.currentDate().addYears(1))
        end_date_label = QLabel('租赁截止日期:')
        end_date_sub_layout.addWidget(end_date_label)
        end_date_sub_layout.setSpacing(2)  # 设置组件间隔为2
        end_date_sub_layout.addWidget(self.end_date_edit)
        lease_date_layout.addLayout(end_date_sub_layout)
        
        # 连接信号和槽,当合同期或开始日期变化时,自动更新截止日期
        self.contract_period_combo.currentTextChanged.connect(self.updateEndDate)
        self.start_date_edit.dateChanged.connect(self.updateEndDate)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(lease_date_layout)
        
        # 租金支付方式
        self.payment_method_edit = QComboBox()
        self.payment_method_edit.addItems(['年', '季', '月'])
        payment_method_label = QLabel('租金支付方式:')
        # 使用全局样式
        form_layout.addRow(payment_method_label, self.payment_method_edit)
        
        # 租金相关字段布局
        rent_layout = QHBoxLayout()
        
        # 月租金额
        self.monthly_rent_edit = QDoubleSpinBox()
        self.monthly_rent_edit.setRange(0.0, 999999.99)
        self.monthly_rent_edit.setDecimals(2)
        self.monthly_rent_edit.setValue(0.00)
        monthly_rent_label = QLabel('月租金额(元):')
        # 使用全局样式
        rent_layout.addWidget(monthly_rent_label)
        rent_layout.addWidget(self.monthly_rent_edit)
        
        # 添加一个间隔
        rent_layout.addStretch()
        
        # 季度租金
        self.quarterly_rent_edit = QDoubleSpinBox()
        self.quarterly_rent_edit.setRange(0.0, 999999.99)
        self.quarterly_rent_edit.setDecimals(2)
        self.quarterly_rent_edit.setValue(0.00)
        self.quarterly_rent_edit.setReadOnly(False)  # 设置为可编辑
        quarterly_rent_label = QLabel('季度租金(元):')
        # 使用全局样式
        rent_layout.addWidget(quarterly_rent_label)
        rent_layout.addWidget(self.quarterly_rent_edit)
        
        # 添加一个间隔
        rent_layout.addStretch()
        
        # 年度租金
        self.yearly_rent_edit = QDoubleSpinBox()
        self.yearly_rent_edit.setRange(0.0, 999999.99)
        self.yearly_rent_edit.setDecimals(2)
        self.yearly_rent_edit.setValue(0.00)
        self.yearly_rent_edit.setReadOnly(False)  # 设置为可编辑
        yearly_rent_label = QLabel('年度租金(元):')
        # 使用全局样式
        rent_layout.addWidget(yearly_rent_label)
        rent_layout.addWidget(self.yearly_rent_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(rent_layout)
        
        # 押金金额
        self.deposit_edit = QDoubleSpinBox()
        self.deposit_edit.setRange(0.0, 999999.99)
        self.deposit_edit.setDecimals(2)
        self.deposit_edit.setValue(0.00)
        deposit_label = QLabel('押金金额(元):')
        # 使用全局样式
        form_layout.addRow(deposit_label, self.deposit_edit)
        
        # 添加实体分隔线
        separator4 = QFrame()
        separator4.setFrameShape(QFrame.HLine)
        separator4.setFrameShadow(QFrame.Sunken)
        form_layout.addRow(separator4)
        
        # 水电费收取方式
        self.utility_method_edit = QComboBox()
        self.utility_method_edit.addItems(['按标准收取', '其它'])
        utility_method_label = QLabel('水电费收取方式:')
        # 使用全局样式
        form_layout.addRow(utility_method_label, self.utility_method_edit)
        
        # 水费标准和电费标准布局
        utility_fee_layout = QHBoxLayout()
        
        # 水费标准
        self.water_fee_edit = QDoubleSpinBox()
        self.water_fee_edit.setRange(0.0, 999999.99)
        self.water_fee_edit.setDecimals(2)
        self.water_fee_edit.setValue(0.00)
        water_fee_label = QLabel('水费标准(元/吨):')
        # 使用全局样式
        utility_fee_layout.addWidget(water_fee_label)
        utility_fee_layout.addWidget(self.water_fee_edit)
        
        # 添加一个间隔
        utility_fee_layout.addStretch()
        
        # 电费标准
        self.electricity_fee_edit = QDoubleSpinBox()
        self.electricity_fee_edit.setRange(0.0, 999999.99)
        self.electricity_fee_edit.setDecimals(2)
        self.electricity_fee_edit.setValue(0.00)
        electricity_fee_label = QLabel('电费标准(元/度):')
        # 使用全局样式
        utility_fee_layout.addWidget(electricity_fee_label)
        utility_fee_layout.addWidget(self.electricity_fee_edit)
        
        # 将水平布局添加到表单布局
        form_layout.addRow(utility_fee_layout)
        
        # 添加实体分隔线
        separator_utility = QFrame()
        separator_utility.setFrameShape(QFrame.HLine)
        separator_utility.setFrameShadow(QFrame.Sunken)
        form_layout.addRow(separator_utility)
        
        # 备注 - 设置高度
        self.remarks_edit = QTextEdit()
        self.remarks_edit.setMinimumHeight(30)  # 最小高度
        self.remarks_edit.setMaximumHeight(30)  # 最大高度
        self.remarks_edit.setFixedHeight(30)    # 固定高度
        remarks_label = QLabel('备注:')
        # 使用全局样式
        form_layout.addRow(remarks_label, self.remarks_edit)
        
        # 添加附件功能（支持多文件上传）
        attachment_layout = QVBoxLayout()
        
        # 添加附件按钮
        button_layout = QHBoxLayout()
        self.attachment_button = QPushButton('添加附件')
        self.clear_attachment_button = QPushButton('清空附件')
        
        # 连接附件按钮点击事件
        self.attachment_button.clicked.connect(self.selectAttachment)
        self.clear_attachment_button.clicked.connect(self.clearAttachments)
        
        button_layout.addWidget(self.attachment_button)
        button_layout.addWidget(self.clear_attachment_button)
        
        # 添加蓝色提示标签
        tip_label = QLabel('<b><font color="red">提示</font></b>:<br>1、点击文件名,可直接打开附件。<br>2、建议将附件放到该程序目录下的文件夹。')
        tip_label.setStyleSheet('font-size: 10px;')
        tip_label.setWordWrap(True)
        button_layout.addWidget(tip_label)
        
        # 添加默认隐藏的"是否续签"文本框
        self.is_renewed_label = QLineEdit('未续签')
        # 设置文本颜色为红色,粗体,并且边框线为红色
        self.is_renewed_label.setStyleSheet('color: red; font-weight: bold; border: 1px solid red;')
        self.is_renewed_label.setReadOnly(True)  # 设置为只读
        self.is_renewed_label.setFixedWidth(60)  # 设置固定宽度
        self.is_renewed_label.setHidden(True)  # 默认隐藏
        button_layout.addWidget(self.is_renewed_label)
        
        # 仅在编辑模式下添加续签按钮,放在是否续签标签后面
        if self.is_edit:
            self.renew_button = QPushButton('续签')
            self.renew_button.clicked.connect(self.handleRenewContract)
            button_layout.addWidget(self.renew_button)
        
        button_layout.addStretch()
        attachment_layout.addLayout(button_layout)

        
        # 创建列表控件显示已上传文件
        self.attachment_list = QListWidget()
        self.attachment_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.attachment_list.setMaximumHeight(40)  # 设置最大高度为40像素
        self.attachment_list.setMinimumHeight(20)  # 设置最小高度为20像素
        # 连接点击事件,用于打开文件
        self.attachment_list.itemClicked.connect(self.openAttachment)
        
        # 存储附件文件路径的列表
        self.attachment_paths = []
        
        attachment_layout.addWidget(self.attachment_list)
        attachment_label = QLabel('附件列表:')
        # 使用全局样式
        form_layout.addRow(attachment_label, attachment_layout)
        
        # 添加表单布局到滚动布局
        scroll_layout.addLayout(form_layout)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 保存按钮
        save_button = QPushButton('保存')
        save_button.clicked.connect(self.accept)
        button_layout.addWidget(save_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(self.reject)
        button_layout.addWidget(cancel_button)
        
        # 续签按钮已移至是否续签标签后方
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 连接信号和槽,当月租金额变化时,自动计算季度租金和年度租金
        self.monthly_rent_edit.valueChanged.connect(self.calculateRents)
        
        # 连接信号和槽,当房屋编号或房屋类型变更时,自动填充水电费标准
        self.house_no_edit.editingFinished.connect(self.onHouseInfoChanged)
        self.house_type_edit.textChanged.connect(self.onHouseInfoChanged)
        
        # 如果是编辑模式,填充数据
        if self.is_edit and self.contract_data:
            self.fillContractData()
        else:
            # 如果是添加合同模式,自动填充默认出租人信息
            self.fillDefaultLandlordInfo()
            # 初始化时更新一次截止日期
            self.updateEndDate()
            
    def calculateRents(self):
        # 计算季度租金和年度租金,并执行四舍五入操作,结果保留为整数
        monthly_rent = self.monthly_rent_edit.value()
        quarterly_rent = round(monthly_rent * 3)  # 四舍五入,保留整数
        yearly_rent = round(monthly_rent * 12)  # 四舍五入,保留整数
        
        self.quarterly_rent_edit.setValue(quarterly_rent)
        self.yearly_rent_edit.setValue(yearly_rent)
    
    def onHouseInfoChanged(self):
        # 当房屋编号或房屋类型变更时,自动填充水电费标准
        house_type = self.house_type_edit.text().strip()
        
        # 如果房屋类型为空,尝试根据房屋编号查询
        if not house_type and self.house_no_edit.text().strip():
            try:
                # 使用DatabaseUtils获取数据库连接
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                cursor = conn.cursor()
                cursor.execute("SELECT house_type FROM houses WHERE house_no = ?", (self.house_no_edit.text().strip(),))
                result = cursor.fetchone()
                if result and result[0]:
                    house_type = result[0]
                    self.house_type_edit.setText(house_type)
                conn.close()
            except Exception as e:
                pass  # 静默处理错误
        
        # 如果有房屋类型,查询并填充水电费标准
        if house_type:
            self.fillUtilityFeesByHouseType(house_type)
        
    def updateEndDate(self):
        # 根据合同期和开始日期更新截止日期（日期值-1）
        start_date = self.start_date_edit.date()
        period_years = int(self.contract_period_combo.currentText())
        end_date = start_date.addYears(period_years)
        # 截止日期减去1天
        end_date = end_date.addDays(-1)
        self.end_date_edit.setDate(end_date)
    
    def fillUtilityFeesByHouseType(self, house_type):
        # 根据房屋类型查询并填充水电费标准
        conn = None
        cursor = None
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT water_fee, electricity_fee FROM utility_fee WHERE house_type = ?", (house_type,))
            result = cursor.fetchone()
            
            if result:
                # 设置水电费标准
                self.water_fee_edit.setValue(float(result[0]))
                self.electricity_fee_edit.setValue(float(result[1]))
        except Exception as e:
            pass  # 静默处理错误
        finally:
            if cursor:
                cursor.close()
            if conn:
                conn.close()
            
    def fillDefaultLandlordInfo(self):
        # 自动填充默认出租人信息
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询默认出租人信息（is_default=1）
            cursor.execute("SELECT landlord_name, legal_representative, person_in_charge, contact_phone FROM landlords WHERE is_default = 1")
            default_landlord = cursor.fetchone()
            
            # 如果存在默认出租人,填充表单
            if default_landlord:
                self.lessor_edit.setText(default_landlord[0] if default_landlord[0] else '')
                self.legal_representative_edit.setText(default_landlord[1] if default_landlord[1] else '')
                self.person_in_charge_edit.setText(default_landlord[2] if default_landlord[2] else '')
                self.contact_phone_edit.setText(default_landlord[3] if default_landlord[3] else '')
            
            # 关闭连接
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            # 发生错误时记录日志,不影响用户体验
            from logger_module import log_error
            log_error(f'加载默认出租人信息时发生错误:{str(e)}')
    
    def handleRenewContract(self):
        # 处理合同续签功能
        # 获取当前登录用户信息
        from user_auth import auth_manager
        current_user = auth_manager.current_user
        current_user_id = auth_manager.current_user_id
        
        # 检查是否已续签
        if hasattr(self, 'is_renewed_label') and self.is_renewed_label.text() == "已续签":
            # 获取合同编号
            contract_no = self.contract_data[1] if hasattr(self, 'contract_data') and self.contract_data and len(self.contract_data) > 1 else ''
            # 显示提示框
            QMessageBox.information(self, '提示', f'该合同（{contract_no}）已续签,不能重复续签!')
            # 终止执行后续操作
            return
        try:
            # 1. 将当前合同状态更新为"已完成"
            self.status_edit.setCurrentText('已完成')
            
            # 2. 显示"是否续签"标签并设置其值为"已续签"
            self.is_renewed_label.setHidden(False)
            self.is_renewed_label.setText("已续签")
            
            # 3. 更新数据库中的is_renewed字段为"已续签"
            if hasattr(self, 'contract_data') and self.contract_data:
                contract_no = self.contract_data[1] if len(self.contract_data) > 1 else ''
                if contract_no:
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    cursor.execute("UPDATE contracts SET is_renewed = '已续签' WHERE contract_no = ?", (contract_no,))
                    conn.commit()
                    conn.close()
                    
                    # 记录操作日志
                    from user_auth import auth_manager
                    record_operation(
                        auth_manager.current_user_id,
                        auth_manager.current_user,
                        "合同管理",
                        "续签合同",
                        "成功",
                        f"将合同 {contract_no} 标记为已续签"
                    )
            
            # 3. 提示用户手动保存合同变更
            # QMessageBox.information(self, '提示', '合同已标记为已完成并显示"已续签"标签,请点击"保存"按钮确认更改。')
            
            # 4. 创建并打开新的添加合同窗口,并填充数据
            # 收集当前合同数据
            contract_data = {
                'house_no': self.house_no_edit.text(),
                'house_type': self.house_type_edit.text(),
                'house_area': self.house_area_edit.value(),
                'purpose': self.purpose_edit.currentText(),
                'house_location': self.house_location_edit.text(),
                'lessor': self.lessor_edit.text(),
                'legal_representative': self.legal_representative_edit.text(),
                'person_in_charge': self.person_in_charge_edit.text(),
                'contact_phone': self.contact_phone_edit.text(),
                'lessee': self.lessee_edit.text(),
                'tenant': self.tenant_edit.text(),
                'tenant_id': self.tenant_id_edit.text(),
                'tenant_phone': self.tenant_phone_edit.text(),
                'monthly_rent': self.monthly_rent_edit.value(),
                'quarterly_rent': self.quarterly_rent_edit.value(),
                'yearly_rent': self.yearly_rent_edit.value(),
                'payment_method': self.payment_method_edit.currentText(),
                'water_fee': self.water_fee_edit.value(),
                'electricity_fee': self.electricity_fee_edit.value(),
                'remarks': self.remarks_edit.toPlainText()
            }
            
            # 创建新的添加合同窗口
            # 注意:这里需要确保能够获取到正确的父窗口或应用实例
            # 由于PyQt的限制,这里使用None作为父窗口
            # 传递空数据,因为我们将手动填充数据
            new_contract_dialog = ContractDialog(is_edit=False, contract_data=None)
            
            # 手动填充数据到新的添加合同窗口
            # 由于ContractDialog构造函数会自动调用initUI,所有控件都已创建完成
            try:
                new_contract_dialog.house_no_edit.setText(contract_data['house_no'])
                new_contract_dialog.house_type_edit.setText(contract_data['house_type'])
                new_contract_dialog.house_area_edit.setValue(contract_data['house_area'])
                new_contract_dialog.purpose_edit.setCurrentText(contract_data['purpose'])
                new_contract_dialog.house_location_edit.setText(contract_data['house_location'])
                new_contract_dialog.lessor_edit.setText(contract_data['lessor'])
                new_contract_dialog.legal_representative_edit.setText(contract_data['legal_representative'])
                new_contract_dialog.person_in_charge_edit.setText(contract_data['person_in_charge'])
                new_contract_dialog.contact_phone_edit.setText(contract_data['contact_phone'])
                new_contract_dialog.lessee_edit.setText(contract_data['lessee'])
                new_contract_dialog.tenant_edit.setText(contract_data['tenant'])
                new_contract_dialog.tenant_id_edit.setText(contract_data['tenant_id'])
                new_contract_dialog.tenant_phone_edit.setText(contract_data['tenant_phone'])
                new_contract_dialog.monthly_rent_edit.setValue(contract_data['monthly_rent'])
                new_contract_dialog.quarterly_rent_edit.setValue(contract_data['quarterly_rent'])
                new_contract_dialog.yearly_rent_edit.setValue(contract_data['yearly_rent'])
                new_contract_dialog.payment_method_edit.setCurrentText(contract_data['payment_method'])
                new_contract_dialog.water_fee_edit.setValue(contract_data['water_fee'])
                new_contract_dialog.electricity_fee_edit.setValue(contract_data['electricity_fee'])
                new_contract_dialog.remarks_edit.setPlainText(contract_data['remarks'])
            except Exception as fill_error:
                pass  # 静默处理错误
            
            # 显示新的添加合同窗口,只有当用户点击确定时才保存合同
            if new_contract_dialog.exec_():
                try:
                    # 获取合同数据 - 使用不同的变量名以避免与前面的contract_data混淆
                    new_contract_data = new_contract_dialog.getContractData()
                    # 新合同数据已获取
                    
                    # 连接数据库并插入数据
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    
                    # 计算签约年月
                    sign_date = datetime.strptime(new_contract_data['sign_date'], '%Y-%m-%d')
                    sign_year_month = f"{sign_date.year}-{sign_date.month:02d}"
                    
                    # 计算年租金总额
                    monthly_rent = new_contract_data['monthly_rent']
                    annual_rent = monthly_rent * 12
                    
                    # 计算租金收款总额
                    try:
                        start_date = datetime.strptime(new_contract_data['start_date'], '%Y-%m-%d')
                        end_date = datetime.strptime(new_contract_data['end_date'], '%Y-%m-%d')
                        months = (end_date.year - start_date.year) * 12 + (end_date.month - start_date.month)
                        total_rent = monthly_rent * months
                    except ValueError as e:
                        QMessageBox.warning(self, '日期格式错误', '请检查起租日期或到期日期格式是否正确!')
                        return
                    
                    # 插入合同数据到数据库 - 使用与标准添加合同功能相同的字段顺序和名称
                    insert_sql = '''
                        INSERT INTO contracts (
                            contract_no, sign_date, sign_year_month, house_no, house_location, house_area,
                            lessor, legal_representative, person_in_charge, contact_phone,
                            lessee, tenant, tenant_id, tenant_phone,
                            start_date, end_date, status, payment_method, monthly_rent, total_rent, annual_rent, deposit,
                            usage, utility_method, water_fee, electricity_fee, remarks, attachment_path, payment_status
                        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                    '''
                    
                    # 确保所有字段都能正确匹配,严格按照数据库表结构顺序
                    cursor.execute(insert_sql, (
                        new_contract_data.get('contract_no', ''),
                        new_contract_data.get('sign_date', ''),
                        sign_year_month,
                        new_contract_data.get('house_no', ''),
                        new_contract_data.get('house_location', ''),
                        new_contract_data.get('house_area', 0),
                        new_contract_data.get('lessor', ''),
                        new_contract_data.get('legal_representative', ''),
                        new_contract_data.get('person_in_charge', ''),
                        new_contract_data.get('contact_phone', ''),
                        new_contract_data.get('lessee', ''),
                        new_contract_data.get('tenant', ''),
                        new_contract_data.get('tenant_id', ''),
                        new_contract_data.get('tenant_phone', ''),
                        new_contract_data.get('start_date', ''),
                        new_contract_data.get('end_date', ''),
                        new_contract_data.get('status', '进行中'),
                        new_contract_data.get('payment_method', ''),
                        new_contract_data.get('monthly_rent', 0),
                        total_rent,  # 租金收款总额
                        annual_rent,  # 年租金总额
                        new_contract_data.get('deposit', 0),
                        new_contract_data.get('usage', ''),  # 使用usage字段,而不是purpose
                        new_contract_data.get('utility_method', ''),  # 新增utility_method字段
                        new_contract_data.get('water_fee', 0),
                        new_contract_data.get('electricity_fee', 0),
                        new_contract_data.get('remarks', ''),
                        new_contract_data.get('attachment_path', '[]'),  # 使用attachment_path字段,而不是attachments
                        new_contract_data.get('payment_status', '未结清')  # 添加收款情况字段
                    ))
                    
                    # 提交事务
                    conn.commit()
                    
                    # 记录操作日志
                    record_operation(
                        self.auth_manager.current_user_id,
                        self.auth_manager.current_user,
                        "合同管理",
                        "续签合同",
                        "成功",
                        f"成功创建新续签合同 {new_contract_data.get('contract_no', '')}"
                    )
                    
                    # 显示成功消息
                    QMessageBox.information(self, '成功', '新合同已成功续签!')
                    
                except Exception as save_error:
                    # 发生错误时回滚事务
                    if conn:
                        conn.rollback()
                    QMessageBox.critical(self, '错误', f'保存新合同数据时发生错误:{str(save_error)}')
                finally:
                    # 关闭数据库连接
                    if cursor:
                        cursor.close()
                    if conn:
                        conn.close()
            
        except Exception as e:
            pass  # 静默处理合同续签错误
            
            # 记录操作日志
            from user_auth import auth_manager
            record_operation(
                auth_manager.current_user_id,
                auth_manager.current_user,
                "合同管理",
                "续签合同",
                "失败",
                f"处理合同续签时发生错误:{str(e)}"
            )
            
            # 显示错误消息给用户
            QMessageBox.critical(self, '错误', f'处理合同续签时发生错误:{str(e)}')
    
    def fillContractData(self):
        # 填充合同数据
        # contract_data 的结构: (id, contract_no, sign_date, sign_year_month, ...)
        # 临时断开信号连接,防止填充数据时触发onHouseInfoChanged方法覆盖水电费标准
        self.house_no_edit.editingFinished.disconnect(self.onHouseInfoChanged)
        self.house_type_edit.textChanged.disconnect(self.onHouseInfoChanged)
        
        self.contract_no_edit.setText(self.contract_data[1])
        # 禁用合同编号编辑
        self.contract_no_edit.setReadOnly(True)
        
        # 签约日期
        if self.contract_data[2]:
            sign_date = QDate.fromString(self.contract_data[2], 'yyyy-MM-dd')
            self.sign_date_edit.setDate(sign_date)
        
        # 房屋编号
        if self.contract_data[4]:
            self.house_no_edit.setText(self.contract_data[4])
            
            # 根据房屋编号查询房屋类型
            try:
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if conn:
                    try:
                        cursor = conn.cursor()
                        cursor.execute("SELECT house_type FROM houses WHERE house_no = ?", (self.contract_data[4],))
                        house_type = cursor.fetchone()
                        if house_type and house_type[0]:
                            self.house_type_edit.setText(house_type[0])
                            # 在编辑模式下,不需要自动填充水电费标准,直接使用合同数据中的值
                            # self.fillUtilityFeesByHouseType(house_type[0])
                    finally:
                        DatabaseUtils.close_connection(conn)
            except Exception as e:
                pass  # 静默处理错误
        
        # 房屋位置
        if self.contract_data[5]:
            self.house_location_edit.setText(self.contract_data[5])
        
        # 房屋面积
        if self.contract_data[6]:
            self.house_area_edit.setValue(float(self.contract_data[6]))
        
        # 出租方（甲方）
        if self.contract_data[7]:
            self.lessor_edit.setText(self.contract_data[7])
        
        # 法定代表人
        if self.contract_data[8]:
            self.legal_representative_edit.setText(self.contract_data[8])
        
        # 分管负责人
        if self.contract_data[9]:
            self.person_in_charge_edit.setText(self.contract_data[9])
        
        # 联系电话
        if self.contract_data[10]:
            self.contact_phone_edit.setText(self.contract_data[10])
        
        # 承租方（乙方）
        if self.contract_data[11]:
            self.lessee_edit.setText(self.contract_data[11])
        
        # 承租人
        if self.contract_data[12]:
            self.tenant_edit.setText(self.contract_data[12])
        
        # 承租人身份证
        if self.contract_data[13]:
            self.tenant_id_edit.setText(self.contract_data[13])
        
        # 承租人电话
        if self.contract_data[14]:
            self.tenant_phone_edit.setText(self.contract_data[14])
        
        # 租赁开始日期
        if self.contract_data[15]:
            start_date = QDate.fromString(self.contract_data[15], 'yyyy-MM-dd')
            self.start_date_edit.setDate(start_date)
        
        # 租赁截止日期
        if self.contract_data[16]:
            end_date = QDate.fromString(self.contract_data[16], 'yyyy-MM-dd')
            self.end_date_edit.setDate(end_date)
            
            # 根据开始日期和截止日期计算合同期并设置
            if hasattr(self, 'contract_period_combo'):
                years = start_date.daysTo(end_date) // 365
                if years >= 1 and years <= 3:
                    self.contract_period_combo.setCurrentText(str(years))
        
        # 合同状态
        if self.contract_data[17]:
            index = self.status_edit.findText(self.contract_data[17])
            if index >= 0:
                self.status_edit.setCurrentIndex(index)
        
        # 租金支付方式
        if self.contract_data[18]:
            index = self.payment_method_edit.findText(self.contract_data[18])
            if index >= 0:
                self.payment_method_edit.setCurrentIndex(index)
        
        # 月租金额
        if self.contract_data[19]:
            self.monthly_rent_edit.setValue(float(self.contract_data[19]))
            # 计算并设置季度租金和年度租金
            self.calculateRents()
        
        # 押金金额
        if self.contract_data[22]:
            self.deposit_edit.setValue(float(self.contract_data[22]))
        
        # 用途
        if self.contract_data[23]:
            index = self.purpose_edit.findText(self.contract_data[23])
            if index >= 0:
                self.purpose_edit.setCurrentIndex(index)
        
        # 水电费收取方式
        if self.contract_data[24]:
            index = self.utility_method_edit.findText(self.contract_data[24])
            if index >= 0:
                self.utility_method_edit.setCurrentIndex(index)
        
        # 水费标准
        if self.contract_data[25]:
            self.water_fee_edit.setValue(float(self.contract_data[25]))
        
        # 电费标准
        if self.contract_data[26]:
            self.electricity_fee_edit.setValue(float(self.contract_data[26]))
        
        # 备注
        if self.contract_data[27]:
            self.remarks_edit.setText(self.contract_data[27])
        
        # 附件路径（支持多个文件）
        if len(self.contract_data) > 30 and self.contract_data[30]:
            try:
                # 解析JSON字符串为列表
                self.attachment_paths = json.loads(self.contract_data[30])
                # 在列表控件中显示所有文件
                self.attachment_list.clear()
                for file_path in self.attachment_paths:
                    if file_path and os.path.exists(file_path):  # 验证文件是否存在
                        file_name = os.path.basename(file_path)
                        item = QListWidgetItem(file_name)
                        item.setToolTip(file_path)
                        self.attachment_list.addItem(item)
            except (json.JSONDecodeError, TypeError):
                # 处理旧版本的单个文件路径
                old_path = self.contract_data[30]
                if old_path:
                    self.attachment_paths = [old_path]
                    file_name = os.path.basename(old_path)
                    item = QListWidgetItem(file_name)
                    item.setToolTip(old_path)
                    self.attachment_list.addItem(item)
        
        # 获取并显示收款情况
        self.updatePaymentStatus()
        
        # 根据合同状态和is_renewed字段值设置"是否续签"标签显示状态
        if self.contract_data[17] == '已完成':
            self.is_renewed_label.setHidden(False)
            # 检查contract_data中是否有is_renewed字段(通常是第33个元素,索引为32)
            if len(self.contract_data) > 32 and self.contract_data[32]:
                # 根据数据库中的is_renewed字段值设置显示文本
                self.is_renewed_label.setText(self.contract_data[32])
            else:
                # 如果没有该字段,默认为"未续签"
                self.is_renewed_label.setText("未续签")
        else:
            self.is_renewed_label.setHidden(True)
            
        # 数据加载完成后,重新连接信号
        self.house_no_edit.editingFinished.connect(self.onHouseInfoChanged)
        self.house_type_edit.textChanged.connect(self.onHouseInfoChanged)
        
    def lockAllFields(self):
        # 锁定所有表单字段,使其不可编辑
        # 日期和编号相关字段
        self.sign_date_edit.setReadOnly(True)
        self.contract_no_edit.setReadOnly(True)
        self.status_edit.setEnabled(False)
        
        # 房屋信息相关字段
        self.house_no_edit.setReadOnly(True)
        self.house_area_edit.setReadOnly(True)
        self.house_location_edit.setReadOnly(True)
        self.purpose_edit.setEnabled(False)
        
        # 出租方信息相关字段
        self.lessor_edit.setReadOnly(True)
        self.legal_representative_edit.setReadOnly(True)
        self.person_in_charge_edit.setReadOnly(True)
        self.contact_phone_edit.setReadOnly(True)
        
        # 承租方信息相关字段
        self.lessee_edit.setReadOnly(True)
        self.tenant_edit.setReadOnly(True)
        self.tenant_id_edit.setReadOnly(True)
        self.tenant_phone_edit.setReadOnly(True)
        
        # 租赁日期相关字段
        self.start_date_edit.setReadOnly(True)
        self.end_date_edit.setReadOnly(True)
        
        # 租金相关字段
        self.payment_method_edit.setEnabled(False)
        self.monthly_rent_edit.setReadOnly(True)
        self.quarterly_rent_edit.setReadOnly(True)
        self.yearly_rent_edit.setReadOnly(True)
        self.deposit_edit.setReadOnly(True)
        
        # 水电费相关字段
        self.utility_method_edit.setEnabled(False)
        self.water_fee_edit.setReadOnly(True)
        self.electricity_fee_edit.setReadOnly(True)
        
        # 备注字段
        self.remarks_edit.setReadOnly(True)
        
        # 附件相关按钮
        self.attachment_button.setEnabled(False)
        self.clear_attachment_button.setEnabled(False)
        # 附件列表设置为只读
        self.attachment_list.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 但仍然允许点击打开文件
        self.attachment_list.setDisabled(False)
        
        # 禁用保存按钮
        for button in self.findChildren(QPushButton):
            if button.text() == '保存':
                button.setEnabled(False)
                break
    
    def updatePaymentStatus(self):
        """更新收款情况显示,优先使用数据库中存储的值"""
        try:
            # 优先使用数据库中存储的payment_status字段值（索引31）
            if hasattr(self, 'contract_data') and self.contract_data and len(self.contract_data) > 31 and self.contract_data[31]:
                payment_status = self.contract_data[31]
                # 收款情况已从数据库获取
            else:
                # 如果数据库中没有值或值为空,则进行计算
                conn = None
                cursor = None
                try:
                    # 连接数据库
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    
                    # 获取合同编号
                    contract_no = self.contract_data[1] if self.contract_data and len(self.contract_data) > 1 else ''
                    
                    if contract_no:
                        # 获取年租金总额（与主界面逻辑保持一致）
                        cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
                        result = cursor.fetchone()
                        annual_rent_value = float(result[0]) if result and result[0] is not None else 0.0
                        annual_rent_value = round(annual_rent_value)  # 四舍五入,保留整数
                        
                        # 获取已收总租金
                        cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
                        result = cursor.fetchone()
                        received_rent = float(result[0]) if result and result[0] is not None else 0.0
                        received_rent = round(received_rent)  # 四舍五入,保留整数
                        
                        # 计算剩余租金（年租金总额 - 已收总租金），确保不会为负数
                        remaining_rent = max(0, annual_rent_value - received_rent)
                        
                        # 设置收款情况文本
                        if remaining_rent != 0:
                            payment_status = "未结清"
                        else:
                            payment_status = "已结清"
                    else:
                        payment_status = "未结清"
                except Exception as e:
                    pass  # 静默处理收款情况计算错误
                    self.payment_status_value_label.setText('获取失败')
                    return
                finally:
                    if cursor:
                        cursor.close()
                    if conn:
                        conn.close()
            
            # 更新标签
            self.payment_status_value_label.setText(payment_status)
            
            # 如果收款情况为已结清,锁定所有字段
            if payment_status == "已结清":
                self.lockAllFields()
        except Exception as e:
            pass  # 静默处理收款情况更新错误
            self.payment_status_value_label.setText('获取失败')
    
    def selectAttachment(self):
        # 打开文件选择对话框,限制文件类型,支持多选
        file_paths, _ = QFileDialog.getOpenFileNames(
            self, 
            '选择附件', 
            '', 
            '支持的文件类型 (*.doc *.docx *.xls *.xlsx *.pdf *.jpg *.jpeg *.png)'
        )
        
        if file_paths:
            # 添加新选择的文件到列表,避免重复
            for file_path in file_paths:
                if file_path not in self.attachment_paths:
                    self.attachment_paths.append(file_path)
                    # 在列表中显示文件名
                    file_name = os.path.basename(file_path)
                    item = QListWidgetItem(file_name)
                    # 设置提示显示完整路径
                    item.setToolTip(file_path)
                    self.attachment_list.addItem(item)
    
    def clearAttachments(self):
        # 清空所有附件
        self.attachment_paths = []
        self.attachment_list.clear()
    
    def openAttachment(self, item):
        # 获取点击的文件名
        file_name = item.text()
        # 查找对应的完整路径
        for file_path in self.attachment_paths:
            if os.path.basename(file_path) == file_name:
                try:
                    # 打开文件
                    if os.name == 'nt':  # Windows系统
                        os.startfile(file_path)
                    else:  # 其他系统
                        import subprocess
                        opener = 'open' if sys.platform == 'darwin' else 'xdg-open'
                        subprocess.run([opener, file_path])
                except Exception as e:
                    QMessageBox.warning(self, '打开文件失败', f'无法打开文件:{str(e)}')
                break
    
    def getContractData(self):
        """获取合同窗口中所有组件的当前值
        
        该方法从合同对话框的各个UI组件中提取数据,将其组织成一个字典返回。
        收集的数据包括合同基本信息、房屋信息、双方当事人信息、租金信息、
        水电费信息、附件信息等,以便保存到数据库中。
        
        Returns:
            dict: 包含所有合同相关数据的字典
        """
        # 获取合同数据
        contract_data = {
            'contract_no': self.contract_no_edit.text(),
            'sign_date': self.sign_date_edit.date().toString('yyyy-MM-dd'),
            'house_no': self.house_no_edit.text(),
            'house_location': self.house_location_edit.text(),
            'house_area': self.house_area_edit.value(),
            'house_type': self.house_type_edit.text(),
            'lessor': self.lessor_edit.text(),
            'legal_representative': self.legal_representative_edit.text(),
            'person_in_charge': self.person_in_charge_edit.text(),
            'contact_phone': self.contact_phone_edit.text(),
            'lessee': self.lessee_edit.text(),
            'tenant': self.tenant_edit.text(),
            'tenant_id': self.tenant_id_edit.text(),
            'tenant_phone': self.tenant_phone_edit.text(),
            'start_date': self.start_date_edit.date().toString('yyyy-MM-dd'),
            'end_date': self.end_date_edit.date().toString('yyyy-MM-dd'),
            'status': self.status_edit.currentText(),
            'payment_method': self.payment_method_edit.currentText(),
            'monthly_rent': self.monthly_rent_edit.value(),
            'quarterly_rent': self.quarterly_rent_edit.value(),
            'deposit': self.deposit_edit.value(),
            'usage': self.purpose_edit.currentText(),
            'utility_method': self.utility_method_edit.currentText(),
            'water_fee': self.water_fee_edit.value(),
            'electricity_fee': self.electricity_fee_edit.value(),
            'remarks': self.remarks_edit.toPlainText(),
            'attachment_path': json.dumps(self.attachment_paths),  # 将附件路径列表转换为JSON字符串
            'payment_status': self.payment_status_value_label.text() if hasattr(self, 'payment_status_value_label') and self.payment_status_value_label.text() else '未结清'
        }
        
        # 确保数值类型的数据转换正确
        for key in ['house_area', 'monthly_rent', 'quarterly_rent', 'deposit', 'water_fee', 'electricity_fee']:
            try:
                if contract_data[key] == '':
                    contract_data[key] = 0.0
                else:
                    contract_data[key] = float(contract_data[key])
            except (ValueError, TypeError):
                contract_data[key] = 0.0
                
        return contract_data
    
    def showHouseSelectionDialog(self):
        # 创建房屋选择对话框
        dialog = QDialog(self)
        dialog.setWindowTitle('选择房屋')
        dialog.resize(600, 400)
        
        # 创建主布局
        main_layout = QVBoxLayout(dialog)
        
        # 创建搜索框
        search_layout = QHBoxLayout()
        search_label = QLabel('搜索:')
        search_input = QLineEdit()
        search_input.setPlaceholderText('输入房屋编号或位置进行搜索')
        search_button = QPushButton('搜索')
        reset_button = QPushButton('重置')
        
        search_layout.addWidget(search_label)
        search_layout.addWidget(search_input)
        search_layout.addWidget(search_button)
        search_layout.addWidget(reset_button)
        main_layout.addLayout(search_layout)
        
        # 创建房屋表格
        house_table = QTableWidget()
        house_table.setColumnCount(4)
        house_table.setHorizontalHeaderLabels(['房屋编号', '房屋位置', '房屋面积', '房屋类型'])
        house_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        house_table.setEditTriggers(QTableWidget.NoEditTriggers)
        house_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 加载房屋数据
        self.loadHouseData(house_table)
        
        # 搜索功能
        def search_houses():
            search_text = search_input.text().lower()
            for row_idx in range(house_table.rowCount()):
                match = False
                for col_idx in range(house_table.columnCount()):
                    item = house_table.item(row_idx, col_idx)
                    if item and search_text in item.text().lower():
                        match = True
                        break
                house_table.setRowHidden(row_idx, not match)
        
        # 重置搜索
        def reset_houses_search():
            search_input.clear()
            search_houses()
        
        search_button.clicked.connect(search_houses)
        search_input.returnPressed.connect(search_houses)
        reset_button.clicked.connect(reset_houses_search)
        
        # 双击选择
        def select_house(row, col):
            house_no = house_table.item(row, 0).text()
            house_location = house_table.item(row, 1).text()
            house_area = house_table.item(row, 2).text()
            house_type = house_table.item(row, 3).text()
            
            # 填充到表单
            self.house_no_edit.setText(house_no)
            self.house_location_edit.setText(house_location)
            if house_area:
                try:
                    self.house_area_edit.setValue(float(house_area))
                except ValueError:
                    pass
            self.house_type_edit.setText(house_type)
            
            # 选择房屋后,自动填充水电费标准
            self.fillUtilityFeesByHouseType(house_type)
            
            dialog.accept()
        
        house_table.cellDoubleClicked.connect(select_house)
        
        # 添加表格到布局
        main_layout.addWidget(house_table)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 确定按钮
        ok_button = QPushButton('确定')
        ok_button.clicked.connect(lambda: dialog.accept())
        button_layout.addWidget(ok_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(lambda: dialog.reject())
        button_layout.addWidget(cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 执行对话框
        dialog.exec_()
    
    def loadHouseData(self, table):
        # 从数据库加载房屋数据
        try:
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                raise Exception("无法获取数据库连接")
            cursor = conn.cursor()
            # 按房屋编号升序排序查询
            cursor.execute("SELECT house_no, house_location, house_area, house_type FROM houses ORDER BY house_no ASC")
            houses = cursor.fetchall()
            
            # 清空表格
            table.setRowCount(0)
            
            # 填充表格
            for row_idx, house in enumerate(houses):
                table.insertRow(row_idx)
                # 房屋编号
                item = QTableWidgetItem(str(house[0]) if house[0] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 0, item)
                # 房屋位置
                item = QTableWidgetItem(str(house[1]) if house[1] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 1, item)
                # 房屋面积
                item = QTableWidgetItem(f"{house[2]:.2f}" if house[2] is not None else '0.00')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 2, item)
                # 房屋类型
                item = QTableWidgetItem(str(house[3]) if house[3] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 3, item)
            
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载房屋数据时发生错误:\n{str(e)}')
    
    def loadTenantData(self, table):
        # 从数据库加载承租人数据
        try:
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                raise Exception("无法获取数据库连接")
            cursor = conn.cursor()
            cursor.execute("SELECT tenant_name, contact_person, contact_id, contact_phone FROM tenants")
            tenants = cursor.fetchall()
            
            # 清空表格
            table.setRowCount(0)
            
            # 填充表格
            for row_idx, tenant in enumerate(tenants):
                table.insertRow(row_idx)
                # 承租方名称
                item = QTableWidgetItem(str(tenant[0]) if tenant[0] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 0, item)
                # 联系人姓名
                item = QTableWidgetItem(str(tenant[1]) if tenant[1] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 1, item)
                # 联系人身份证
                item = QTableWidgetItem(str(tenant[2]) if tenant[2] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 2, item)
                # 联系人电话
                item = QTableWidgetItem(str(tenant[3]) if tenant[3] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 3, item)
            
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载承租人数据时发生错误:\n{str(e)}')
            
    def loadLandlordData(self, table):
        # 从数据库加载出租人数据
        try:
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if not conn:
                raise Exception("无法获取数据库连接")
            cursor = conn.cursor()
            cursor.execute("SELECT landlord_name, legal_representative, person_in_charge, contact_phone FROM landlords")
            landlords = cursor.fetchall()
            
            # 清空表格
            table.setRowCount(0)
            
            # 填充表格
            for row_idx, landlord in enumerate(landlords):
                table.insertRow(row_idx)
                # 出租方名称
                item = QTableWidgetItem(str(landlord[0]) if landlord[0] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 0, item)
                # 法定代表人
                item = QTableWidgetItem(str(landlord[1]) if landlord[1] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 1, item)
                # 分管负责人
                item = QTableWidgetItem(str(landlord[2]) if landlord[2] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 2, item)
                # 联系电话
                item = QTableWidgetItem(str(landlord[3]) if landlord[3] is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                table.setItem(row_idx, 3, item)
            
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载出租人数据时发生错误:\n{str(e)}')
    
    def showLandlordSelectionDialog(self):
        # 创建出租人选择对话框
        dialog = QDialog(self)
        dialog.setWindowTitle('选择出租人')
        dialog.resize(600, 400)
        
        # 创建主布局
        main_layout = QVBoxLayout(dialog)
        
        # 创建搜索框
        search_layout = QHBoxLayout()
        search_label = QLabel('搜索:')
        search_input = QLineEdit()
        search_input.setPlaceholderText('输入出租人名称或法定代表人进行搜索')
        search_button = QPushButton('搜索')
        reset_button = QPushButton('重置')
        
        search_layout.addWidget(search_label)
        search_layout.addWidget(search_input)
        search_layout.addWidget(search_button)
        search_layout.addWidget(reset_button)
        main_layout.addLayout(search_layout)
        
        # 创建出租人表格
        landlord_table = QTableWidget()
        landlord_table.setColumnCount(4)
        landlord_table.setHorizontalHeaderLabels(['出租人名称', '法定代表人', '分管负责人', '联系电话'])
        landlord_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        landlord_table.setEditTriggers(QTableWidget.NoEditTriggers)
        landlord_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 加载出租人数据
        self.loadLandlordData(landlord_table)
        
        # 搜索功能
        def search_landlords():
            search_text = search_input.text().lower()
            for row_idx in range(landlord_table.rowCount()):
                match = False
                for col_idx in range(landlord_table.columnCount()):
                    item = landlord_table.item(row_idx, col_idx)
                    if item and search_text in item.text().lower():
                        match = True
                        break
                landlord_table.setRowHidden(row_idx, not match)
        
        # 重置搜索
        def reset_landlords_search():
            search_input.clear()
            search_landlords()
        
        search_button.clicked.connect(search_landlords)
        search_input.returnPressed.connect(search_landlords)
        reset_button.clicked.connect(reset_landlords_search)
        
        # 双击选择
        def select_landlord(row, col):
            landlord_name = landlord_table.item(row, 0).text()
            legal_representative = landlord_table.item(row, 1).text()
            person_in_charge = landlord_table.item(row, 2).text()
            contact_phone = landlord_table.item(row, 3).text()
            
            # 填充到表单
            self.lessor_edit.setText(landlord_name)
            self.legal_representative_edit.setText(legal_representative)
            self.person_in_charge_edit.setText(person_in_charge)
            self.contact_phone_edit.setText(contact_phone)
            
            dialog.accept()
        
        landlord_table.cellDoubleClicked.connect(select_landlord)
        
        # 添加表格到布局
        main_layout.addWidget(landlord_table)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 确定按钮
        ok_button = QPushButton('确定')
        ok_button.clicked.connect(lambda: dialog.accept())
        button_layout.addWidget(ok_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(lambda: dialog.reject())
        button_layout.addWidget(cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 执行对话框
        dialog.exec_()
        
    def showTenantSelectionDialog(self):
        # 创建承租人选择对话框
        dialog = QDialog(self)
        dialog.setWindowTitle('选择承租人')
        dialog.resize(600, 400)
        
        # 创建主布局
        main_layout = QVBoxLayout(dialog)
        
        # 创建搜索框
        search_layout = QHBoxLayout()
        search_label = QLabel('搜索:')
        search_input = QLineEdit()
        search_input.setPlaceholderText('输入承租人名称或联系人进行搜索')
        search_button = QPushButton('搜索')
        reset_button = QPushButton('重置')
        
        search_layout.addWidget(search_label)
        search_layout.addWidget(search_input)
        search_layout.addWidget(search_button)
        search_layout.addWidget(reset_button)
        main_layout.addLayout(search_layout)
        
        # 创建承租人表格
        tenant_table = QTableWidget()
        tenant_table.setColumnCount(4)
        tenant_table.setHorizontalHeaderLabels(['承租方名称', '联系人姓名', '联系人身份证', '联系人电话'])
        tenant_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        tenant_table.setEditTriggers(QTableWidget.NoEditTriggers)
        tenant_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 加载承租人数据
        self.loadTenantData(tenant_table)
        
        # 搜索功能
        def search_tenants():
            search_text = search_input.text().lower()
            for row_idx in range(tenant_table.rowCount()):
                match = False
                for col_idx in range(tenant_table.columnCount()):
                    item = tenant_table.item(row_idx, col_idx)
                    if item and search_text in item.text().lower():
                        match = True
                        break
                tenant_table.setRowHidden(row_idx, not match)
        
        # 重置搜索
        def reset_tenants_search():
            search_input.clear()
            search_tenants()
        
        search_button.clicked.connect(search_tenants)
        search_input.returnPressed.connect(search_tenants)
        reset_button.clicked.connect(reset_tenants_search)
        
        # 双击选择
        def select_tenant(row, col):
            tenant_name = tenant_table.item(row, 0).text()
            contact_person = tenant_table.item(row, 1).text()
            contact_id = tenant_table.item(row, 2).text()
            contact_phone = tenant_table.item(row, 3).text()
            
            # 填充到表单
            self.lessee_edit.setText(tenant_name)
            self.tenant_edit.setText(contact_person)
            self.tenant_id_edit.setText(contact_id)
            self.tenant_phone_edit.setText(contact_phone)
            
            dialog.accept()
        
        tenant_table.cellDoubleClicked.connect(select_tenant)
        
        # 添加表格到布局
        main_layout.addWidget(tenant_table)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 确定按钮
        ok_button = QPushButton('确定')
        ok_button.clicked.connect(lambda: dialog.accept())
        button_layout.addWidget(ok_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(lambda: dialog.reject())
        button_layout.addWidget(cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 执行对话框
        dialog.exec_()
    
    def accept(self):
        # 验证数据
        if not self.contract_no_edit.text():
            QMessageBox.warning(self, '警告', '合同编号不能为空!')
            return
        
        if not self.lessee_edit.text():
            QMessageBox.warning(self, '警告', '承租方（乙方）不能为空!')
            return
        
        if self.start_date_edit.date() > self.end_date_edit.date():
            QMessageBox.warning(self, '警告', '租赁开始日期不能晚于租赁截止日期!')
            return
        
        # 调用父类的accept方法
        super().accept()
    
    def resizeEvent(self, event):
        """重写窗口调整大小事件处理方法"""
        # 调用父类的resizeEvent
        super().resizeEvent(event)
        
        # 使用定时器延迟调整列宽，避免频繁调整导致闪烁
        current_time = time.time() * 1000  # 转换为毫秒
        if self.last_resize_time is None or \
           (current_time - self.last_resize_time) > 200:  # 200ms间隔
            self.resize_timer.start(100)  # 100ms后执行调整
            self.last_resize_time = current_time
    
    def _adjust_column_widths_on_resize(self):
        """窗口大小变化时调整列宽"""
        if not hasattr(self, 'contract_table'):
            return
            
        # 获取表格的可视区域宽度
        viewport_width = self.contract_table.viewport().width()
        
        # 计算所有列的总宽度
        total_columns_width = sum(self.contract_table.columnWidth(col) 
                                 for col in range(self.contract_table.columnCount()))
        
        # 只有当可视区域宽度与列总宽度相差较大时才调整
        if abs(viewport_width - total_columns_width) > 50:  # 50像素的容差
            # 先设置为固定宽度，避免闪烁
            for col in range(self.contract_table.columnCount()):
                current_width = self.contract_table.columnWidth(col)
                self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Fixed)
            
            # 找到需要拉伸的列（通常是内容较长的列）
            stretch_columns = [4]  # 房屋位置列
            
            # 为拉伸列设置Interactive模式，允许用户调整
            for col in stretch_columns:
                if col < self.contract_table.columnCount():
                    self.contract_table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Interactive)
            
            # 确保'租金支付方式'列标题在窗口调整大小时保持两行显示和10号字体样式
            payment_method_col = 10  # 租金支付方式列的索引
            if payment_method_col < self.contract_table.columnCount():
                # 重新设置表头项，保持两行显示和10号字体
                header_item = QTableWidgetItem('租金\n支付方式')
                header_item.setTextAlignment(Qt.AlignCenter)
                
                font = header_item.font()
                font.setPointSize(9)
                header_item.setFont(font)
                
                self.contract_table.setHorizontalHeaderItem(payment_method_col, header_item)
                
                # 确保表头高度足够显示两行
                header = self.contract_table.horizontalHeader()
                header.setMinimumHeight(max(header.height(), 40))
            
            # 为所有列标题设置字体大小（比默认小1个单位）
            header_font = QFont()
            header_font.setPointSize(9)  # 设置为9号字体
            for col in range(self.contract_table.columnCount()):
                header_item = self.contract_table.horizontalHeaderItem(col)
                if header_item:
                    header_item.setFont(header_font)
            
            # 对于非常长的内容，可以考虑限制最大宽度
            max_width = viewport_width // 3  # 最大宽度不超过可视区域的1/3
            for col in range(self.contract_table.columnCount()):
                if self.contract_table.columnWidth(col) > max_width:
                    self.contract_table.setColumnWidth(col, max_width)

# 租金管理标签页
class RentTab(QWidget):
    # 导入全局auth_manager
    from user_auth import auth_manager
    # 定义数据更新信号
    data_updated = pyqtSignal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent  # 保存父窗口引用
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建搜索和操作按钮区域
        search_layout = QHBoxLayout()
        
        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText('搜索所有非数字字段（合同编号、承租方、承租人、房屋位置等）')
        search_layout.addWidget(self.search_input)
        
        # 搜索按钮
        search_button = QPushButton('搜索')
        search_button.clicked.connect(self.searchRentRecords)
        search_layout.addWidget(search_button)
        
        # 重置按钮
        reset_button = QPushButton('重置')
        reset_button.clicked.connect(self.resetSearch)
        search_layout.addWidget(reset_button)
        
        # 绑定回车事件
        self.search_input.returnPressed.connect(self.searchRentRecords)
        
        # 添加租金记录按钮
        add_button = QPushButton('添加租金记录')
        add_button.clicked.connect(self.addRentRecord)
        search_layout.addWidget(add_button)
        
        # 编辑租金记录按钮
        self.edit_button = QPushButton('编辑租金记录')
        self.edit_button.clicked.connect(self.editRentRecord)
        self.edit_button.setEnabled(False)
        search_layout.addWidget(self.edit_button)
        
        # 删除租金记录按钮
        self.delete_button = QPushButton('删除租金记录')
        self.delete_button.clicked.connect(self.deleteRentRecord)
        self.delete_button.setEnabled(False)
        search_layout.addWidget(self.delete_button)
        
        # 导出按钮
        export_button = QPushButton('导出数据')
        export_button.clicked.connect(self.exportRentRecords)
        search_layout.addWidget(export_button)
        
        # 添加搜索和操作按钮区域到主布局
        main_layout.addLayout(search_layout)
        
        # 创建租金记录表格
        self.rent_table = QTableWidget()
        self.rent_table.setColumnCount(10)  # 增加一列用于显示房屋编号和收款情况
        self.rent_table.setHorizontalHeaderLabels(['合同编号', '房屋编号', '承租方', '承租人', '收款日期', '收款金额', '所属期间', '收款账户', '收款情况', '说明'])
        
        # 设置表格属性
        # 优化列宽设置，使各列分布更均匀，视觉比例更合理
        header = self.rent_table.horizontalHeader()
        
        # 根据各列内容特点设置不同的宽度策略
        # 合同编号：固定宽度，长度相对固定
        header.setSectionResizeMode(0, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(0, 120)
        
        # 房屋编号：固定宽度，长度相对固定
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(1, 100)
        
        # 承租方：适中宽度，可能包含较长文本
        header.setSectionResizeMode(2, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(2, 200)
        
        # 承租人：适中宽度
        header.setSectionResizeMode(3, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(3, 160)
        
        # 收款日期：固定宽度，格式一致
        header.setSectionResizeMode(4, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(4, 140)
        
        # 收款金额：适中宽度
        header.setSectionResizeMode(5, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(5, 120)
        
        # 所属期间：固定宽度，格式一致
        header.setSectionResizeMode(6, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(6, 180)
        
        # 收款账户：适中宽度
        header.setSectionResizeMode(7, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(7, 150)
        
        # 收款情况：固定宽度，状态标识
        header.setSectionResizeMode(8, QHeaderView.Fixed)
        self.rent_table.setColumnWidth(8, 150)
        
        # 说明：拉伸模式，占据剩余空间，允许显示更多文本内容
        header.setSectionResizeMode(9, QHeaderView.Stretch)
        
        self.rent_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.rent_table.setSelectionBehavior(QTableWidget.SelectRows)
        self.rent_table.cellClicked.connect(self.onCellClicked)
        self.rent_table.cellDoubleClicked.connect(self.onCellDoubleClicked)
        
        # 初始化排序状态
        self.current_sort_column = -1  # 当前排序列
        self.current_sort_order = Qt.AscendingOrder  # 当前排序顺序
        # 连接表头点击信号到排序处理函数
        header.sectionClicked.connect(self.on_rent_table_header_clicked)
        # 启用排序
        self.rent_table.setSortingEnabled(False)  # 先禁用自动排序，使用自定义排序
        
        # 添加租金记录表格到主布局
        main_layout.addWidget(self.rent_table)
        
        # 创建统计信息区域
        stats_layout = QHBoxLayout()
        
        # 创建统计标签
        self.total_count_label = QLabel('合计笔数: 0')
        self.settled_count_label = QLabel('已结清笔数: 0')
        self.unsettled_count_label = QLabel('未结清笔数: 0')
        self.total_amount_label = QLabel('收款总金额: ¥0.00')
        
        # 设置标签样式
        font = QFont()
        font.setPointSize(11)
        font.setBold(False)
        
        self.total_count_label.setFont(font)
        self.settled_count_label.setFont(font)
        self.unsettled_count_label.setFont(font)
        self.total_amount_label.setFont(font)
        
        # 添加标签到布局
        stats_layout.addWidget(self.total_count_label)
        stats_layout.addWidget(self.settled_count_label)
        stats_layout.addWidget(self.unsettled_count_label)
        stats_layout.addStretch()
        stats_layout.addWidget(self.total_amount_label)
        
        # 将统计信息区域添加到主布局
        main_layout.addLayout(stats_layout)
    
    def loadRentRecords(self, conn):
        # 从数据库加载租金记录数据,通过合同编号关联获取房屋编号
        cursor = conn.cursor()
        # 使用LEFT JOIN连接contracts表,获取房屋编号信息
        cursor.execute("""
            SELECT r.contract_no, c.house_no, r.lessee, r.tenant, r.receipt_date, 
                   r.amount, r.period_start, r.period_end, r.account, r.description 
            FROM rent_records r
            LEFT JOIN contracts c ON r.contract_no = c.contract_no
        """)
        rent_records = cursor.fetchall()
        
        # 自定义排序函数:按房屋编号升序排列
        # 数值部分按0-9顺序,中文字符部分按首字母A-Z顺序
        def customSort(record):
            house_no = record[1] if len(record) > 1 else ''
            house_no = str(house_no) if house_no is not None else ''
            
            # 提取数值部分
            num_part = ''
            for char in house_no:
                if char.isdigit():
                    num_part += char
                else:
                    break
            
            # 如果有数值部分,转换为整数,否则设为0
            num_value = int(num_part) if num_part else 0
            
            # 提取中文/非数值部分
            non_num_part = house_no[len(num_part):] if num_part else house_no
            
            # 返回一个元组作为排序键:(数值部分, 非数值部分)
            return (num_value, non_num_part)
        
        # 对租金记录数据进行排序
        sorted_rent_records = sorted(rent_records, key=customSort)
        
        # 清空表格
        self.rent_table.setRowCount(0)
        
        # 存储每条记录的原始数据和收款情况
        all_records = []
        payment_status_list = []
        
        # 添加数据到表格
        for row_idx, record in enumerate(sorted_rent_records):
            self.rent_table.insertRow(row_idx)
            # 合同编号
            item = QTableWidgetItem(record[0] if record[0] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 0, item)
            # 房屋编号
            item = QTableWidgetItem(record[1] if record[1] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 1, item)
            # 承租方
            item = QTableWidgetItem(record[2] if record[2] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 2, item)
            # 承租人
            item = QTableWidgetItem(record[3] if record[3] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 3, item)
            # 收款日期
            item = QTableWidgetItem(record[4] if record[4] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 4, item)
            # 收款金额
            if record[5] is not None:
                # 处理带千位分隔符的金额字符串
                cleaned_amount = str(record[5]).replace(',', '')
                # 四舍五入保留整数
                amount = round(float(cleaned_amount))
                # 添加千分符并设置格式
                item = QTableWidgetItem(f"{amount:,}" if amount else '0')
            else:
                item = QTableWidgetItem('0')
            # 设置为水平靠右对齐
            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.rent_table.setItem(row_idx, 5, item)
            # 所属期间
            period = f"{record[6]} 至 {record[7]}" if record[6] and record[7] else ''
            item = QTableWidgetItem(period)
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 6, item)
            # 收款账户
            item = QTableWidgetItem(record[8] if record[8] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 7, item)
            
            # 收款情况
            contract_no = record[0] if record[0] is not None else ''
            if contract_no:
                # 查询合同的年租金总额
                cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
                contract = cursor.fetchone()
                if contract:
                    annual_rent_value = float(contract[0]) if contract[0] is not None else 0
                    
                    # 查询该合同已收总租金
                    cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
                    result = cursor.fetchone()
                    received_rent = float(result[0]) if result[0] is not None else 0
                    received_rent = round(received_rent)  # 四舍五入,保留整数
                    
                    # 计算剩余租金（年租金总额 - 已收总租金），确保不会为负数
                    remaining_rent = max(0, annual_rent_value - received_rent)
                    remaining_rent = round(remaining_rent)  # 四舍五入,保留整数
                    
                    # 判断收款情况
                    if remaining_rent != 0:
                        payment_status = "未结清"
                    else:
                        payment_status = "已结清"
                else:
                    payment_status = "合同不存在"
            else:
                payment_status = "未知"
            item = QTableWidgetItem(payment_status)
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 8, item)
            
            # 说明
            item = QTableWidgetItem(record[9] if record[9] is not None else '')
            item.setTextAlignment(Qt.AlignCenter)
            self.rent_table.setItem(row_idx, 9, item)
            
            # 保存记录数据和收款情况
            all_records.append((row_idx, record, payment_status))
            payment_status_list.append(payment_status)
        
        # 按合同编号分组,找出每组中收款日期最晚的记录
        contract_latest_dates = {}
        for row_idx, record, payment_status in all_records:
            contract_no = record[0] if record[0] is not None else ''
            receipt_date = record[4] if record[4] is not None else ''
            
            if contract_no and receipt_date:
                if contract_no not in contract_latest_dates or receipt_date > contract_latest_dates[contract_no][1]:
                    contract_latest_dates[contract_no] = (row_idx, receipt_date)
        
        # 获取当前日期和30天后的日期
        import datetime
        current_date = datetime.date.today()
        # 获取提醒设置
        contract_reminder_days, rent_reminder_days = self.parent.getReminderSettings()
        # 根据租金到期提醒天数计算提醒日期
        reminder_date = current_date + datetime.timedelta(days=rent_reminder_days)
        
        # 对符合条件的记录设置红色加粗样式
        matched_count = 0  # 用于记录匹配的记录数量
        
        for row_idx, record, payment_status in all_records:
            contract_no = record[0] if record[0] is not None else ''
            receipt_date = record[4] if record[4] is not None else ''
            period_end = record[7] if record[7] is not None else ''
            
            # 检查条件1:收款情况为"未结清"
            condition1 = payment_status == "未结清"
            
            # 检查条件2:是同合同编号中收款日期最晚的记录
            condition2 = False
            if contract_no in contract_latest_dates:
                latest_row_idx, latest_date = contract_latest_dates[contract_no]
                condition2 = (row_idx == latest_row_idx)
            
            # 检查条件3:所属期间的截止日期在未来30天内（含30天当天）或已逾期
            condition3 = False
            if period_end:
                try:
                    # 将日期字符串转换为date对象
                    # 尝试多种日期格式解析
                    date_formats = ["%Y-%m-%d", "%Y/%m/%d", "%d-%m-%Y", "%d/%m/%Y"]
                    end_date = None
                    for fmt in date_formats:
                        try:
                            end_date = datetime.datetime.strptime(period_end, fmt).date()
                            break
                        except ValueError:
                            continue
                    
                    if end_date:
                        # 检查是否在租金到期提醒天数内或已逾期
                        condition3 = (end_date <= reminder_date)
                except Exception as e:
                    # 捕获所有异常并记录
                    log_error(f"日期解析错误: {str(e)}", exc_info=True)
                    pass
            
            # 打印调试信息
            log_debug(f"行 {row_idx}, 合同 {contract_no}, 收款情况: {payment_status}, 条件1: {condition1}, 条件2: {condition2}, 条件3: {condition3}")
            
            # 如果同时满足三个条件,设置所有列的文本字体为红色并加粗
            if condition1 and condition2 and condition3:
                matched_count += 1
                log_debug(f"行 {row_idx} 匹配所有条件,设置红色加粗样式")
                
                # 检查是否为深色主题
                is_dark_theme = 'dark' in self.parent.styleSheet().lower()
                
                # 对符合条件的单元格应用加粗字体样式并设置字体颜色为红色
                for col_idx in range(self.rent_table.columnCount()):
                    item = self.rent_table.item(row_idx, col_idx)
                    if item:
                        # 创建新字体对象并设置为系统默认字体大小
                        new_font = QFont()
                        new_font.setBold(True)  # 应用加粗样式
                        item.setFont(new_font)
                        
                        # 使用setForeground和setBackground方法，这通常比setData有更高优先级
                        if is_dark_theme:
                            # 深色主题：使用亮红色文本和深色背景
                            item.setForeground(QBrush(QColor(255, 100, 100)))  # 亮红色文本
                            item.setBackground(QBrush(QColor(60, 30, 30)))    # 深红色背景
                        else:
                            # 浅色主题：使用标准红色文本和淡黄色背景
                            item.setForeground(QBrush(QColor(255, 0, 0)))     # 红色文本
                            item.setBackground(QBrush(QColor(255, 255, 200)))  # 淡黄色背景
            
            # 应用新的条件格式:如果收款情况为"未结清",设置整行背景色
            elif payment_status == "未结清":
                # 检查是否为深色主题
                is_dark_theme = 'dark' in self.parent.styleSheet().lower()
                
                for col_idx in range(self.rent_table.columnCount()):
                    item = self.rent_table.item(row_idx, col_idx)
                    if item:
                        # 使用setBackground方法，这通常比setData有更高优先级
                        if is_dark_theme:
                            # 深色主题：使用深蓝色背景
                            item.setBackground(QBrush(QColor(30, 30, 60)))
                        else:
                            # 浅色主题：使用淡黄色背景
                            item.setBackground(QBrush(QColor(255, 255, 200)))
        
        # 记录匹配的记录数量
        log_info(f"租金列表中满足条件的记录数量: {matched_count}")
        
        # 数据加载完成后重新调整列宽，确保所有内容都能完全显示
        header = self.rent_table.horizontalHeader()
        # 先为所有列设置自适应内容模式
        for i in range(10):
            header.setSectionResizeMode(i, QHeaderView.ResizeToContents)
        # 再将最后一列设置为拉伸模式
        header.setSectionResizeMode(9, QHeaderView.Stretch)
        
        # 更新统计信息
        self.updateStatistics()
    
    def onCellClicked(self, row, col):
        # 当单元格被点击时启用编辑和删除按钮
        self.edit_button.setEnabled(True)
        self.delete_button.setEnabled(True)
    
    def onCellDoubleClicked(self, row, col):
        # 当单元格被双击时打开编辑租金记录窗口
        # 设置当前选中行
        self.rent_table.selectRow(row)
        # 调用编辑租金记录方法
        self.editRentRecord()
    
    def on_rent_table_header_clicked(self, column):
        # 处理表头点击事件
        # 切换排序顺序
        if column == self.current_sort_column:
            # 如果点击的是当前排序列，则切换排序顺序
            self.current_sort_order = Qt.DescendingOrder if self.current_sort_order == Qt.AscendingOrder else Qt.AscendingOrder
        else:
            # 如果点击的是新列，则重置排序状态
            self.current_sort_column = column
            self.current_sort_order = Qt.AscendingOrder
        
        # 执行排序
        self.sort_rent_table(column, self.current_sort_order)
        
        # 更新表头指示
        self.update_header_sort_indicator()
    
    def sort_rent_table(self, column, order):
        # 自定义排序函数
        # 禁用表格更新以提高性能
        self.rent_table.setUpdatesEnabled(False)
        
        # 获取表格数据
        rows = self.rent_table.rowCount()
        cols = self.rent_table.columnCount()
        table_data = []
        
        for row in range(rows):
            row_data = []
            for col in range(cols):
                item = self.rent_table.item(row, col)
                if item:
                    row_data.append(item.text())
                else:
                    row_data.append('')
            # 保存原始行索引用于恢复样式
            row_data.append(row)
            table_data.append(row_data)
        
        # 定义排序键函数
        def sort_key(row_data):
            value = row_data[column]
            # 尝试将数字字符串转换为浮点数进行排序
            if column == 5:  # 收款金额列
                try:
                    # 移除千分符并转换为浮点数
                    return float(value.replace(',', ''))
                except ValueError:
                    return 0
            # 尝试将日期字符串转换为日期对象进行排序
            elif column == 4:  # 收款日期列
                try:
                    # 尝试多种日期格式
                    date_formats = ["%Y-%m-%d", "%Y/%m/%d", "%d-%m-%Y", "%d/%m/%Y"]
                    for fmt in date_formats:
                        try:
                            return datetime.strptime(value, fmt)
                        except ValueError:
                            continue
                    return datetime.min  # 无法解析的日期放在最前面
                except Exception:
                    return datetime.min
            # 其他列按字符串排序
            return value
        
        # 执行排序
        table_data.sort(key=sort_key, reverse=(order == Qt.DescendingOrder))
        
        # 清空表格并重新填充
        self.rent_table.setRowCount(0)
        for row_data in table_data:
            original_row = row_data.pop()  # 获取原始行索引
            row_idx = self.rent_table.rowCount()
            self.rent_table.insertRow(row_idx)
            
            # 重新填充数据并恢复原始样式
            for col_idx, value in enumerate(row_data):
                # 创建新单元格
                item = QTableWidgetItem(value)
                item.setTextAlignment(Qt.AlignCenter if col_idx != 5 else Qt.AlignRight | Qt.AlignVCenter)
                
                # 尝试恢复原始样式
                original_item = self.rent_table.item(original_row, col_idx)
                if original_item:
                    # 恢复字体样式
                    item.setFont(original_item.font())
                    # 恢复前景色
                    if original_item.data(Qt.ForegroundRole):
                        item.setData(Qt.ForegroundRole, original_item.data(Qt.ForegroundRole))
                        item.setForeground(original_item.foreground())
                    # 恢复背景色
                    if original_item.data(Qt.BackgroundRole):
                        item.setData(Qt.BackgroundRole, original_item.data(Qt.BackgroundRole))
                        item.setBackground(original_item.background())
                
                self.rent_table.setItem(row_idx, col_idx, item)
        
        # 恢复表格更新
        self.rent_table.setUpdatesEnabled(True)
    
    def update_header_sort_indicator(self):
        # 更新表头排序指示
        header = self.rent_table.horizontalHeader()
        
        # 清除所有列的排序指示
        for i in range(self.rent_table.columnCount()):
            header.setSortIndicatorShown(False)
        
        # 在当前排序列显示排序指示
        if self.current_sort_column >= 0:
            header.setSortIndicator(self.current_sort_column, self.current_sort_order)
            header.setSortIndicatorShown(True)
    
    def updateStatistics(self):
        # 计算统计数据 - 基于表格中当前显示的记录
        total_count = 0
        settled_count = 0
        unsettled_count = 0
        total_amount = 0
        
        for row_idx in range(self.rent_table.rowCount()):
            # 只计算未隐藏的行
            if not self.rent_table.isRowHidden(row_idx):
                total_count += 1
                
                # 获取收款金额
                amount_item = self.rent_table.item(row_idx, 5)
                if amount_item and amount_item.text():
                    try:
                        # 移除千分符再转换为浮点数
                        amount = float(amount_item.text().replace(',', ''))
                        total_amount += amount
                    except ValueError:
                        pass
                
                # 获取收款情况
                status_item = self.rent_table.item(row_idx, 8)
                if status_item and status_item.text():
                    payment_status = status_item.text()
                    if payment_status == '已结清':
                        settled_count += 1
                    elif payment_status == '未结清':
                        unsettled_count += 1
        
        # 更新统计标签
        self.total_count_label.setText(f'合计笔数: {total_count}')
        self.settled_count_label.setText(f'已结清笔数: {settled_count}')
        self.unsettled_count_label.setText(f'未结清笔数: {unsettled_count}')
        self.total_amount_label.setText(f'收款总金额: ¥{total_amount:.2f}')
    
    def resetSearch(self):
        """
        重置搜索框并显示所有记录
        
        功能: 清空搜索输入框内容,并执行搜索功能以显示所有记录
        """
        self.search_input.clear()
        self.searchRentRecords()
    
    def searchRentRecords(self):
        # 搜索租金记录
        search_text = self.search_input.text().lower()
        
        for row_idx in range(self.rent_table.rowCount()):
            match = False
            for col_idx in range(self.rent_table.columnCount()):
                item = self.rent_table.item(row_idx, col_idx)
                if item and search_text in item.text().lower():
                    match = True
                    break
            
            self.rent_table.setRowHidden(row_idx, not match)
        
        # 更新统计信息
        self.updateStatistics()
    
    def addRentRecord(self):
        """
        添加新的租金记录
        
        功能: 创建新的租金收款记录,包括显示添加对话框、收集租金信息、保存到数据库
        
        实现步骤:
            1. 显示租金记录添加对话框
            2. 收集用户输入的租金记录数据
            3. 连接数据库并插入新的租金记录
            4. 重新加载租金记录列表,显示最新数据
            5. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、数据完整性约束违反、数据格式错误等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始添加租金记录")
            
            # 显示租金记录添加对话框（非模态）
            dialog = RentRecordDialog()
            
            # 定义保存租金记录的函数
            def saveRentRecord():
                try:
                    # 获取租金记录数据
                    rent_data = dialog.getRentData()
                    log_debug(f"获取到租金记录数据: 合同编号={rent_data['contract_no']}, 金额={rent_data['amount']}")
                    
                    # 连接数据库并插入数据
                    from db_utils import DatabaseUtils
                    conn = None
                    cursor = None
                    
                    try:
                        conn = DatabaseUtils.get_connection()
                        if not conn:
                            raise Exception("无法获取数据库连接")
                        cursor = conn.cursor()
                        
                        # 开始事务处理
                        conn.execute("BEGIN TRANSACTION")
                        
                        try:
                            # 从rent_data中获取收款情况（已在getRentData方法中处理和标准化）
                            payment_status = rent_data.get('payment_status', '未结清')
                            # 确保状态值有效
                            if payment_status not in ['已结清', '未结清']:
                                payment_status = '未结清'
                            
                            # 插入数据
                            cursor.execute(
                                '''INSERT INTO rent_records (
                                    contract_no, lessee, tenant, receipt_date, amount, period_start, period_end, account, invoice_date, description, payment_status, house_no, payment_method, monthly_rent
                                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                                (
                                    rent_data['contract_no'], rent_data['lessee'], rent_data['tenant'],
                                    rent_data['receipt_date'], rent_data['amount'],
                                    rent_data['period_start'], rent_data['period_end'],
                                    rent_data['account'], rent_data['invoice_date'],
                                    rent_data['description'], payment_status,
                                    rent_data['house_no'], rent_data['payment_method'], rent_data['monthly_rent']
                                )
                            )
                            
                            # 同步更新该合同编号的所有租金记录的收款情况
                            cursor.execute(
                                '''UPDATE rent_records SET payment_status = ? WHERE contract_no = ?''',
                                (payment_status, rent_data['contract_no'])
                            )
                            log_debug(f"同步更新合同 {rent_data['contract_no']} 的所有租金记录收款情况为: {payment_status}")
                            
                            # 更新合同表中的收款情况
                            cursor.execute(
                                '''UPDATE contracts SET payment_status = ? WHERE contract_no = ?''',
                                (payment_status, rent_data['contract_no'])
                            )
                            log_debug(f"更新合同表中合同 {rent_data['contract_no']} 的收款情况为: {payment_status}")
                            
                            # 根据要求：若收款情况为"已结清"且所属期间截止日期小于或等于当前日期，更新合同状态为"已完成"
                            if payment_status == '已结清':
                                from datetime import datetime
                                current_date = datetime.now().date()
                                period_end = datetime.strptime(rent_data['period_end'], '%Y-%m-%d').date()
                                
                                if period_end <= current_date:
                                    cursor.execute(
                                        '''UPDATE contracts SET status = '已完成' WHERE contract_no = ?''',
                                        (rent_data['contract_no'],)
                                    )
                                    log_debug(f"更新合同 {rent_data['contract_no']} 的状态为: 已完成")
                            log_debug(f"成功执行租金记录插入SQL: 合同编号={rent_data['contract_no']}")
                            
                            # 提交事务
                            conn.commit()
                            log_info(f"成功添加租金记录: 合同编号={rent_data['contract_no']}, 金额={rent_data['amount']}")
                            
                            # 记录操作日志 - 操作成功
                            from operation_logger import record_operation
                            record_operation(
                                self.auth_manager.current_user_id,
                                self.auth_manager.current_user,
                                "租金管理",
                                "添加租金记录",
                                "成功",
                                f"合同编号: {rent_data['contract_no']}, 收款日期: {rent_data['receipt_date']}, 金额: {rent_data['amount']}"
                            )
                            
                            # 显示成功消息
                            QMessageBox.information(self, '添加成功', f'租金记录添加成功!')
                            
                            # 清空表单,以便继续添加新记录
                            # 重新初始化表单,清空所有输入框
                            dialog.initUI()
                        except sqlite3.IntegrityError as e:
                            conn.rollback()
                            log_error(f"租金记录数据完整性错误: {str(e)}")
                            
                            # 记录操作日志 - 操作失败
                            from operation_logger import record_operation
                            record_operation(
                                self.auth_manager.current_user_id,
                                self.auth_manager.current_user,
                                "租金管理",
                                "添加租金记录",
                                "失败",
                                f"合同编号: {rent_data['contract_no']}, 错误信息: {str(e)}"
                            )
                            
                            QMessageBox.warning(self, '添加失败', f'租金记录数据不完整或违反完整性约束!\n错误信息: {str(e)}')
                            return
                        except sqlite3.Error as e:
                            conn.rollback()
                            log_error(f"数据库错误: {str(e)}")
                            
                            # 记录操作日志 - 操作失败
                            from operation_logger import record_operation
                            record_operation(
                                self.auth_manager.current_user_id,
                                self.auth_manager.current_user,
                                "租金管理",
                                "添加租金记录",
                                "失败",
                                f"合同编号: {rent_data['contract_no']}, 错误信息: {str(e)}"
                            )
                            
                            QMessageBox.warning(self, '添加失败', f'数据库操作失败!\n错误信息: {str(e)}')
                            return
                    except Exception as e:
                        if conn:
                            conn.rollback()
                        log_error(f"数据库操作失败: {str(e)}")
                        QMessageBox.warning(self, '操作失败', f'数据库操作失败!\n错误信息: {str(e)}')
                        return
                    finally:
                        # 关闭数据库连接
                        if cursor:
                            cursor.close()
                        if conn:
                            DatabaseUtils.close_connection(conn)
                        log_debug("数据库连接已关闭")
                    
                    # 重新加载租金记录数据
                    try:
                        from db_utils import DatabaseUtils
                        conn = DatabaseUtils.get_connection()
                        if conn:
                            try:
                                self.loadRentRecords(conn)
                                log_debug("租金记录列表已更新")
                            finally:
                                DatabaseUtils.close_connection(conn)
                    except Exception as e:
                        log_error(f"重新加载租金记录数据失败: {str(e)}")
                    
                    # 发送数据更新信号
                    self.data_updated.emit()
                    log_debug("发送数据更新信号")
                except Exception as e:
                    log_error(f"保存租金记录过程中发生错误: {str(e)}")
                    QMessageBox.critical(self, '系统错误', f'保存租金记录失败!\n错误信息: {str(e)}')
            
            # 连接信号
            dialog.data_saved.connect(saveRentRecord)
            
            # 显示对话框
            dialog.show()
        except Exception as e:
            log_error(f"添加租金记录过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            from operation_logger import record_operation
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="租金管理",
                operation_content="添加租金记录",
                operation_result="异常",
                detail={"错误信息": str(e)}
        )
    
    def optimizeDatabase(self):
        """数据库优化功能 - 执行数据库性能优化操作"""
        from database_optimization import DatabaseOptimizer, OptimizerConfig
        
        log_info("开始数据库优化操作")
        
        # 权限验证 - 确保用户具有系统设置权限
        if not self.main_frame.isVisible():
            log_warning("用户权限不足，无法执行数据库优化")
            QMessageBox.warning(self, '权限不足', '您没有执行数据库优化的权限')
            return
        
        # 确认操作
        reply = QMessageBox.question(self, '确认', '数据库优化将执行索引重建、碎片整理和冗余数据清理等操作。\n\n操作完成后系统将自动重启以应用优化效果。是否继续？',
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            log_info("用户取消了数据库优化操作")
            return
        
        # 显示加载状态
        progress_dialog = QProgressDialog('正在执行数据库优化...', None, 0, 100, self)
        progress_dialog.setWindowTitle('数据库优化')
        progress_dialog.setWindowModality(Qt.WindowModal)
        progress_dialog.setMinimumDuration(0)
        progress_dialog.setValue(0)
        progress_dialog.show()
        
        # 进度回调函数
        def update_progress(progress, message):
            """更新进度对话框"""
            if progress >= 0:
                progress_dialog.setValue(progress)
                progress_dialog.setLabelText(message)
                QApplication.processEvents()  # 处理UI事件
            else:
                # 错误状态
                progress_dialog.setLabelText(f"错误: {message}")
        
        # 执行优化操作
        try:
            # 禁用所有与数据库相关的操作，防止数据不一致
            self.create_db_btn.setEnabled(False)
            self.select_db_btn.setEnabled(False)
            self.backup_btn.setEnabled(False)
            self.restore_btn.setEnabled(False)
            self.init_btn.setEnabled(False)
            self.optimize_db_btn.setEnabled(False)
            self.view_log_btn.setEnabled(False)
            
            update_progress(10, "正在初始化优化器...")
            
            # 获取数据库连接
            conn = self.db_manager.get_connection()
            
            # 创建优化器配置
            config = OptimizerConfig()
            
            # 创建优化器实例
            optimizer = DatabaseOptimizer(config)
            
            log_info("开始执行数据库优化操作")
            
            # 执行优化，传入连接和进度回调
            result = optimizer.optimize(connection=conn, progress_callback=update_progress)
            
            # 提交更改
            conn.commit()
            
            log_info(f"数据库优化操作完成，结果: {result.success}")
            
            # 关闭连接
            self.db_manager.return_connection(conn)
            
            if result.success:
                # 显示成功消息
                QMessageBox.information(self, '成功', '数据库优化成功，系统将自动重启以应用优化效果')
                
                # 记录操作成功日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="系统设置",
                    operation_content="数据库优化",
                    operation_result="成功",
                    detail={
                        "操作": "完成数据库优化",
                        "优化表数": result.tables_optimized,
                        "执行时间": f"{result.get_duration():.2f}秒"
                    }
                )
                
                # 延迟重启应用
                QTimer.singleShot(1000, self.restartApplication)
            else:
                # 显示失败消息
                error_msg = f"数据库优化部分操作失败\n\n完成步骤: {len(result.steps_completed)}\n失败步骤: {len(result.steps_failed)}"
                if result.errors:
                    error_msg += f"\n\n错误信息:\n{chr(10).join(result.errors[:3])}"
                
                QMessageBox.warning(self, '优化完成但有警告', error_msg)
                
                # 记录操作结果日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="系统设置",
                    operation_content="数据库优化",
                    operation_result="部分成功",
                    detail={
                        "完成步骤": result.steps_completed,
                        "失败步骤": result.steps_failed,
                        "错误信息": result.errors[:3]  # 只记录前3个错误
                    }
                )
            
        except Exception as e:
            log_error(f"数据库优化失败: {str(e)}")
            QMessageBox.critical(self, '错误', f'数据库优化失败: {str(e)}')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="数据库优化",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
        finally:
            # 重新启用数据库操作
            self.create_db_btn.setEnabled(True)
            self.select_db_btn.setEnabled(True)
            self.backup_btn.setEnabled(True)
            self.restore_btn.setEnabled(True)
            self.init_btn.setEnabled(True)
            self.optimize_db_btn.setEnabled(True)
            self.view_log_btn.setEnabled(True)
    
    def restartApplication(self):
        """重启应用程序以应用数据库优化效果"""
        log_info("系统开始重启以应用数据库优化效果")
        QApplication.quit()
        
        # 重新启动应用
        import sys
        import os
        
        # 获取当前应用路径
        app_path = os.path.abspath(sys.argv[0])
        
        # 启动新实例
        log_info(f"启动应用程序新实例: {app_path}")
        QProcess.startDetached(app_path)
    
    def selectDatabase(self):
        """选择数据库文件并立即切换到新数据库"""
        from db_utils import DatabaseUtils
        from PyQt5.QtWidgets import QFileDialog, QMessageBox
        import sqlite3
        
        try:
            # 打开文件选择对话框
            file_path, _ = QFileDialog.getOpenFileName(
                self, 
                '选择数据库文件', 
                '', 
                'SQLite数据库文件 (*.db);;所有文件 (*.*)'
            )
            
            if file_path:
                # 验证选择的文件是否为有效的SQLite数据库
                try:
                    conn = sqlite3.connect(file_path)
                    cursor = conn.cursor()
                    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
                    tables = cursor.fetchall()
                    conn.close()
                    
                    # 检查是否包含必要的表
                    required_tables = ['contracts', 'users', 'reminder_settings']
                    found_tables = [table[0] for table in tables]
                    
                    missing_tables = [table for table in required_tables if table not in found_tables]
                    
                    if missing_tables:
                        reply = QMessageBox.question(
                            self,
                            '警告',
                            '所选数据库文件缺少以下必要表: ' + ', '.join(missing_tables) + '继续使用此数据库可能导致程序功能异常,是否继续?',
                            QMessageBox.Yes | QMessageBox.No,
                            QMessageBox.No
                        )
                        if reply != QMessageBox.Yes:
                            return
                    
                    # 保存当前数据库路径,用于回滚
                    old_db_path = DatabaseUtils.get_db_path()
                    
                    # 设置新的数据库路径
                    log_info(f"开始切换数据库,新路径: {file_path}")
                    DatabaseUtils.set_db_path(file_path)
                    log_info(f"DatabaseUtils数据库路径已更新: {DatabaseUtils.get_db_path()}")
                    
                    # 保存新的数据库路径到配置文件
                    from config_utils import ConfigManager
                    save_result = ConfigManager.set_database_path(file_path)
                    log_info(f"配置文件保存结果: {'成功' if save_result else '失败'}")
                    log_info(f"从配置读取验证: {ConfigManager.get_database_path()}")
                    
                    # 验证新数据库连接是否正常
                    test_conn = DatabaseUtils.get_connection()
                    if test_conn is None:
                        # 连接失败,回滚到原数据库
                        log_error("无法连接到新选择的数据库,回滚到原路径")
                        DatabaseUtils.set_db_path(old_db_path)
                        QMessageBox.critical(
                            self,
                            '错误',
                            '无法连接到新选择的数据库,请检查文件是否有效。'
                        )
                        return
                    else:
                        # 查询新数据库表信息以验证
                        cursor = test_conn.cursor()
                        cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
                        tables = cursor.fetchall()
                        table_names = [table[0] for table in tables]
                        log_info(f"成功连接到新数据库,表列表: {table_names}")
                        DatabaseUtils.close_connection(test_conn)
                    
                    # 刷新系统数据
                    log_info("开始刷新系统数据...")
                    self.refreshSystemData()
                    log_info("数据库切换和数据刷新完成")
                    
                    # 显示成功消息
                    QMessageBox.information(
                        self,
                        '成功',
                        '数据库切换成功!系统已加载新数据库的数据。'
                    )
                    
                    # 记录操作日志
                    self.record_operation(
                        user_id=self.auth_manager.current_user_id,
                        username=self.auth_manager.current_user,
                        operation_module="系统设置",
                        operation_content="选择数据库",
                        operation_result="成功",
                        detail={"数据库路径": file_path}
                    )
                    
                    # 提示用户数据库切换成功
                    QMessageBox.information(
                        self,
                        '成功',
                        '数据库选择成功!系统已切换到新的数据库。'
                    )
                    
                except Exception as e:
                    QMessageBox.critical(
                        self,
                        '错误',
                        f'选择的文件不是有效的SQLite数据库: {str(e)}'
                    )
                    return
        
        except Exception as e:
            QMessageBox.critical(
                self,
                '错误',
                f'选择数据库失败: {str(e)}'
            )
            # 记录错误日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="选择数据库",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
    
    def refreshSystemData(self):
        """刷新系统数据,确保所有模块使用新的数据库"""
        try:
            # 重新加载用户数据
            self.loadUserData()
            
            # 重新加载提醒设置
            self.loadReminderSettings()
            
            # 重新加载软件信息
            self.loadSoftwareInfo()
            
            # 如果存在主窗口,通知其刷新数据
            if hasattr(self.parent(), 'refreshAllData'):
                self.parent().refreshAllData()
                
        except Exception as e:
            # 记录错误但不影响主流程
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="刷新系统数据",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
            
            QMessageBox.critical(self, '系统错误', f'刷新系统数据失败!\n错误信息: {str(e)}')
    
    def editRentRecord(self):
        """
        编辑租金记录
        
        功能: 修改已存在的租金记录信息,包括获取当前租金记录数据、显示编辑对话框、保存更新后的信息
        
        实现步骤:
            1. 检查是否选择了要编辑的租金记录
            2. 获取选中租金记录的合同编号、收款日期和金额
            3. 从数据库中获取该租金记录的详细信息和相关合同信息
            4. 显示编辑对话框并填充现有数据
            5. 收集用户修改后的租金记录数据
            6. 更新数据库中的租金记录信息
            7. 重新加载租金记录列表,显示最新数据
            8. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、数据格式异常、记录不存在等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始编辑租金记录")
            
            # 编辑租金记录
            selected_rows = self.rent_table.selectionModel().selectedRows()
            if not selected_rows:
                log_warning("用户未选择要编辑的租金记录")
                QMessageBox.warning(self, '警告', '请先选择要编辑的租金记录!')
                return
            
            row = selected_rows[0].row()
            contract_no = self.rent_table.item(row, 0).text()
            receipt_date = self.rent_table.item(row, 4).text()
            amount = self.rent_table.item(row, 5).text()
            log_debug(f"选择的租金记录: 合同编号={contract_no}, 收款日期={receipt_date}, 金额={amount}")
            
            # 连接数据库并获取租金记录详细信息,同时获取相关合同信息
            from db_utils import DatabaseUtils
            conn = None
            cursor = None
            rent_record = None
            
            try:
                # 使用DatabaseUtils获取数据库连接
                conn = DatabaseUtils.get_connection()
                if not conn:
                    raise Exception("无法获取数据库连接")
                cursor = conn.cursor()
                
                # 处理带千位分隔符的金额字符串,确保健壮性
                try:
                    cleaned_amount = str(amount).replace(',', '') if isinstance(amount, str) else str(amount)
                    amount_value = float(cleaned_amount)
                    log_debug(f"处理后的金额值: {amount_value}")
                except ValueError as e:
                    log_error(f"金额格式错误: {str(e)}")
                    QMessageBox.warning(self, '数据格式错误', '无法解析金额格式,请检查输入!')
                    return
                
                # 查询租金记录详细信息
                try:
                    # 明确指定返回列的顺序,确保与fillRentData方法中期望的结构一致
                    cursor.execute(
                        "SELECT r.id, r.contract_no, r.lessee, r.tenant, r.receipt_date, r.amount, "
                        "r.period_start, r.period_end, r.account, r.invoice_date, r.description, "
                        "c.house_no, c.payment_method, c.monthly_rent, r.payment_status, "
                        "c.start_date, c.end_date FROM rent_records r "
                        "LEFT JOIN contracts c ON r.contract_no = c.contract_no "
                        "WHERE r.contract_no = ? AND r.receipt_date = ? AND r.amount = ?",
                        (contract_no, receipt_date, amount_value)
                    )
                    rent_record = cursor.fetchone()
                    log_debug(f"成功获取租金记录详细信息: {contract_no}, {receipt_date}")
                except sqlite3.Error as e:
                    log_error(f"查询租金记录失败: {str(e)}")
                    QMessageBox.warning(self, '查询失败', f'获取租金记录信息时出错!\n错误信息: {str(e)}')
                    return
            except Exception as e:
                log_error(f"数据库连接失败: {str(e)}")
                QMessageBox.warning(self, '连接失败', f'无法连接到数据库!\n错误信息: {str(e)}')
                return
            finally:
                if cursor:
                    cursor.close()
                if conn:
                    conn.close()
                log_debug("数据库连接已关闭")
            
            if not rent_record:
                log_error(f"找不到租金记录: 合同编号={contract_no}, 收款日期={receipt_date}, 金额={amount}")
                QMessageBox.warning(self, '警告', '找不到该租金记录的详细信息!')
                return
            
            # 创建对话框并填充数据
            dialog = RentRecordDialog(is_edit=True, rent_data=rent_record)
            
            # 编辑模式:连接data_saved信号到保存逻辑
            def save_edited_record():
                # 保存编辑后的租金记录数据
                rent_data = dialog.getRentData()
                log_debug(f"获取到更新后的租金记录数据: 合同编号={rent_data['contract_no']}")
                
                # 连接数据库并更新数据
                try:
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    
                    # 开始事务处理
                    conn.execute("BEGIN TRANSACTION")
                    
                    try:
                        # 从rent_data中获取收款情况（已在getRentData方法中处理和标准化）
                        payment_status = rent_data.get('payment_status', '未结清')
                        # 确保状态值有效
                        if payment_status not in ['已结清', '未结清']:
                            payment_status = '未结清'
                        
                        # 更新数据
                        cursor.execute(
                            '''UPDATE rent_records SET 
                                contract_no = ?, lessee = ?, tenant = ?, receipt_date = ?, amount = ?, 
                                period_start = ?, period_end = ?, account = ?, invoice_date = ?, description = ?, payment_status = ? 
                            WHERE id = ?''',
                            (
                                rent_data['contract_no'], rent_data['lessee'], rent_data['tenant'],
                                rent_data['receipt_date'], rent_data['amount'],
                                rent_data['period_start'], rent_data['period_end'],
                                rent_data['account'], rent_data['invoice_date'],
                                rent_data['description'], payment_status, rent_record[0]
                            )
                        )
                        
                        # 同步更新该合同编号的所有租金记录的收款情况
                        cursor.execute(
                            '''UPDATE rent_records SET payment_status = ? WHERE contract_no = ?''',
                            (payment_status, rent_data['contract_no'])
                        )
                        log_debug(f"同步更新合同 {rent_data['contract_no']} 的所有租金记录收款情况为: {payment_status}")
                        
                        # 更新合同表中的收款情况
                        cursor.execute(
                            '''UPDATE contracts SET payment_status = ? WHERE contract_no = ?''',
                            (payment_status, rent_data['contract_no'])
                        )
                        log_debug(f"更新合同表中合同 {rent_data['contract_no']} 的收款情况为: {payment_status}")
                        
                        # 根据要求：若收款情况为"已结清"且所属期间截止日期小于或等于当前日期，更新合同状态为"已完成"
                        if payment_status == '已结清':
                            from datetime import datetime
                            current_date = datetime.now().date()
                            period_end = datetime.strptime(rent_data['period_end'], '%Y-%m-%d').date()
                            
                            if period_end <= current_date:
                                cursor.execute(
                                    '''UPDATE contracts SET status = '已完成' WHERE contract_no = ?''',
                                    (rent_data['contract_no'],)
                                )
                                log_debug(f"更新合同 {rent_data['contract_no']} 的状态为: 已完成")
                        log_debug(f"成功执行租金记录更新SQL: ID={rent_record[0]}")
                        
                        # 提交事务
                        conn.commit()
                        log_info(f"成功更新租金记录: ID={rent_record[0]}")
                        
                        # 记录操作日志 - 操作成功
                        from operation_logger import record_operation
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="租金管理",
                            operation_content="编辑租金记录",
                            operation_result="成功",
                            detail={"ID": rent_record[0], "合同编号": rent_data['contract_no'], "收款日期": rent_data['receipt_date']}
                        )
                        
                        # 显示成功消息
                        QMessageBox.information(self, '更新成功', f'租金记录更新成功!')
                    except sqlite3.IntegrityError as e:
                        conn.rollback()
                        log_error(f"租金记录数据完整性错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        from operation_logger import record_operation
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="租金管理",
                            operation_content="编辑租金记录",
                            operation_result="失败",
                            detail={"ID": rent_record[0], "错误信息": str(e)}
                        )
                        
                        QMessageBox.critical(self, '错误', f'租金记录数据完整性错误:{str(e)}')
                    except Exception as e:
                        conn.rollback()
                        log_error(f"更新租金记录时发生错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        from operation_logger import record_operation
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="租金管理",
                            operation_content="编辑租金记录",
                            operation_result="失败",
                            detail={"ID": rent_record[0], "错误信息": str(e)}
                        )
                        
                        QMessageBox.critical(self, '错误', f'更新租金记录时发生错误:{str(e)}')
                    finally:
                        if conn:
                            conn.close()
                            log_debug("数据库连接已关闭")
                except Exception as e:
                    log_error(f"连接数据库时发生错误: {str(e)}")
                    
                    # 记录操作日志 - 操作失败
                    from operation_logger import record_operation
                    record_operation(
                        user_id=self.auth_manager.current_user_id,
                        username=self.auth_manager.current_user,
                        operation_module="租金管理",
                        operation_content="编辑租金记录",
                        operation_result="失败",
                        detail={"错误信息": str(e)}
                    )
                    
                    QMessageBox.critical(self, '错误', f'连接数据库时发生错误:{str(e)}')
            
            dialog.data_saved.connect(save_edited_record)
            dialog.exec_()
            
            # 重新加载租金记录数据
            try:
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if conn:
                    self.loadRentRecords(conn)
                    log_debug("租金记录列表已更新")
                else:
                    log_error("无法获取数据库连接")
            except Exception as e:
                log_error(f"重新加载租金记录数据失败: {str(e)}")
            finally:
                if conn:
                    DatabaseUtils.close_connection(conn)
            
            # 发送数据更新信号
            self.data_updated.emit()
            log_debug("发送数据更新信号")
        except Exception as e:
            log_error(f"编辑租金记录过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            from operation_logger import record_operation
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="租金管理",
                operation_content="编辑租金记录",
                operation_result="异常",
                detail={"错误信息": str(e)}
            )
            
            QMessageBox.critical(self, '系统错误', f'编辑租金记录失败!\n错误信息: {str(e)}')
    
    def deleteRentRecord(self):
        """
        删除租金记录
        
        功能: 从系统中删除选定的租金记录,并确保删除操作不会导致数据不一致
        
        实现步骤:
            1. 检查是否选择了要删除的租金记录
            2. 获取选中租金记录的合同编号、收款日期和金额
            3. 检查合同收款情况,已结清的合同禁止删除租金记录
            4. 确认删除操作
            5. 从数据库中删除指定的租金记录
            6. 重新加载租金记录列表,显示最新数据
            7. 发送数据更新信号,通知相关组件刷新
        
        异常:
            数据库操作异常、数据格式异常、合同信息不存在等都会被捕获并记录日志,同时显示错误提示
        """
        try:
            log_info("开始删除租金记录")
            
            # 删除租金记录
            selected_rows = self.rent_table.selectionModel().selectedRows()
            if not selected_rows:
                log_warning("用户未选择要删除的租金记录")
                QMessageBox.warning(self, '警告', '请先选择要删除的租金记录!')
                return
            
            row = selected_rows[0].row()
            contract_no = self.rent_table.item(row, 0).text()
            receipt_date = self.rent_table.item(row, 4).text()
            amount = self.rent_table.item(row, 5).text()
            log_debug(f"选择的租金记录: 合同编号={contract_no}, 收款日期={receipt_date}, 金额={amount}")
            
            # 检查收款情况
            try:
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                if not conn:
                    log_error("无法获取数据库连接")
                    QMessageBox.warning(self, '连接失败', '无法连接到数据库!')
                    return
                cursor = conn.cursor()
                
                # 查询年租金总额
                try:
                    cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
                    result = cursor.fetchone()
                    if not result:
                        log_error(f"找不到合同信息: {contract_no}")
                        QMessageBox.warning(self, '警告', '找不到该合同信息!')
                        return
                    
                    annual_rent_value = float(result[0]) if result[0] is not None else 0
                    log_debug(f"获取合同年租金: {annual_rent_value}")
                except sqlite3.Error as e:
                    log_error(f"查询年租金总额失败: {str(e)}")
                    QMessageBox.warning(self, '查询失败', f'获取年租金总额时出错!\n错误信息: {str(e)}')
                    return
                except ValueError as e:
                    log_error(f"年租金格式错误: {str(e)}")
                    QMessageBox.warning(self, '数据格式错误', '年租金数据格式错误!')
                    return
                
                # 查询已收总租金
                try:
                    cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
                    result = cursor.fetchone()
                    received_rent = float(result[0]) if result[0] is not None else 0
                    received_rent = round(received_rent)  # 四舍五入,保留整数
                    log_debug(f"合同已收租金总额: {received_rent}")
                except sqlite3.Error as e:
                    log_error(f"查询已收租金总额失败: {str(e)}")
                    QMessageBox.warning(self, '查询失败', f'获取已收租金总额时出错!\n错误信息: {str(e)}')
                    return
                except ValueError as e:
                    log_error(f"已收租金计算错误: {str(e)}")
                    QMessageBox.warning(self, '数据计算错误', '计算已收租金时出错!')
                    return
                
                # 计算剩余租金，确保不会为负数
                remaining_rent = max(0, annual_rent_value - received_rent)
                remaining_rent = round(remaining_rent)  # 四舍五入,保留整数
                log_debug(f"剩余未收租金: {remaining_rent}")
                
                # 判断收款情况
                if remaining_rent == 0:
                    log_warning(f"合同已结清,禁止删除租金记录: {contract_no}")
                    QMessageBox.warning(self, '警告', '该合同收款情况为已结清,禁止删除租金记录!')
                    return
                
            except Exception as e:
                log_error(f"检查收款情况时发生错误: {str(e)}")
                QMessageBox.critical(self, '错误', f'检查收款情况时发生错误:\n{str(e)}')
                return
            finally:
                if 'conn' in locals() and conn:
                    DatabaseUtils.close_connection(conn)
                    log_debug("数据库连接已关闭")
            
            # 确认删除
            reply = QMessageBox.question(self, '确认删除', f'确定要删除合同编号为{contract_no}的租金记录吗?\n删除后将无法恢复!',
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                log_info(f"用户确认删除租金记录: {contract_no}, {receipt_date}, {amount}")
                # 连接数据库并删除数据
                try:
                    conn = DatabaseUtils.get_connection()
                    if not conn:
                        log_error("无法获取数据库连接")
                        QMessageBox.warning(self, '连接失败', '无法连接到数据库!')
                        return
                    cursor = conn.cursor()
                    
                    # 开始事务处理
                    conn.execute("BEGIN TRANSACTION")
                    
                    try:
                        # 删除数据 - 处理带千位分隔符的金额
                        # 先移除字符串中的逗号,再转换为浮点数
                        try:
                            cleaned_amount = str(amount).replace(',', '') if isinstance(amount, str) else str(amount)
                            amount_value = float(cleaned_amount)
                            log_debug(f"处理后的金额值: {amount_value}")
                        except ValueError as e:
                            log_error(f"金额格式错误: {str(e)}")
                            QMessageBox.warning(self, '数据格式错误', '无法解析金额格式,请检查输入!')
                            return
                        
                        cursor.execute(
                            "DELETE FROM rent_records WHERE contract_no = ? AND receipt_date = ? AND amount = ?",
                            (contract_no, receipt_date, amount_value)
                        )
                        
                        # 检查是否有记录被删除
                        if cursor.rowcount == 0:
                            conn.rollback()
                            log_error(f"未找到要删除的租金记录: {contract_no}, {receipt_date}, {amount_value}")
                            QMessageBox.warning(self, '删除失败', '未找到要删除的租金记录!')
                            return
                        
                        log_debug(f"成功执行租金记录删除SQL,影响行数: {cursor.rowcount}")
                        
                        # 提交事务
                        conn.commit()
                        log_info(f"成功删除租金记录: {contract_no}, {receipt_date}")
                        
                        # 记录操作日志 - 操作成功
                        from operation_logger import record_operation
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="租金管理",
                            operation_content="删除租金记录",
                            operation_result="成功",
                            detail={"合同编号": contract_no, "收款日期": receipt_date, "金额": amount}
                        )
                        
                        # 重新加载租金记录数据
                        try:
                            self.loadRentRecords(conn)
                            log_debug("租金记录列表已更新")
                        except Exception as e:
                            log_error(f"重新加载租金记录数据失败: {str(e)}")
                        
                        # 发送数据更新信号
                        self.data_updated.emit()
                        log_debug("发送数据更新信号")
                        
                        # 提示删除成功
                        QMessageBox.information(self, '删除成功', '租金记录已成功删除!')
                    except sqlite3.Error as e:
                        conn.rollback()
                        log_error(f"删除租金记录时数据库错误: {str(e)}")
                        
                        # 记录操作日志 - 操作失败
                        from operation_logger import record_operation
                        record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="租金管理",
                            operation_content="删除租金记录",
                            operation_result="失败",
                            detail={"合同编号": contract_no, "错误信息": str(e)}
                        )
                        
                        QMessageBox.warning(self, '删除失败', f'删除租金记录时数据库错误!\n错误信息: {str(e)}')
                        return
                except Exception as e:
                    if conn:
                        conn.rollback()
                    log_error(f"删除租金记录时操作失败: {str(e)}")
                    QMessageBox.warning(self, '操作失败', f'删除租金记录时操作失败!\n错误信息: {str(e)}')
                    return
                finally:
                    # 关闭数据库连接
                    if 'cursor' in locals() and cursor:
                        cursor.close()
                    if 'conn' in locals() and conn:
                        DatabaseUtils.close_connection(conn)
                    log_debug("数据库连接已关闭")
        except Exception as e:
            log_error(f"删除租金记录过程中发生未预期的错误: {str(e)}")
            
            # 记录操作日志 - 操作异常
            from operation_logger import record_operation
            record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="租金管理",
                operation_content="删除租金记录",
                operation_result="异常",
                detail={"错误信息": str(e)}
            )
            
            QMessageBox.critical(self, '系统错误', f'删除租金记录失败!\n错误信息: {str(e)}')
    
    def exportRentRecords(self):
        # 导出租金记录数据
        # 如果表格为空,提示用户
        if self.rent_table.rowCount() == 0:
            QMessageBox.warning(self, '警告', '当前没有可导出的数据,请先查询或加载租金记录!')
            return
        
        # 创建导出数据对话框
        dialog = ExportDataDialog(self)
        if dialog.exec_():
            # 获取选择的导出格式
            export_format = dialog.getExportFormat()
            
            # 创建导出文件目录
            export_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '导出文件')
            if not os.path.exists(export_dir):
                os.makedirs(export_dir)
            
            # 从表格中获取当前显示的记录数据
            headers = []
            data = []
            
            # 获取表头
            for col_idx in range(self.rent_table.columnCount()):
                headers.append(self.rent_table.horizontalHeaderItem(col_idx).text())
            
            # 获取表格内容
            for row_idx in range(self.rent_table.rowCount()):
                # 跳过隐藏的行
                if self.rent_table.isRowHidden(row_idx):
                    continue
                
                row_data = []
                for col_idx in range(self.rent_table.columnCount()):
                    item = self.rent_table.item(row_idx, col_idx)
                    row_data.append(item.text() if item else '')
                data.append(row_data)
            
            # 生成文件名
            # today = date.today().strftime('%Y%m%d_%H%M%S')
            today = datetime.now().strftime("%Y%m%d_%H%M%S")
            try:
                if export_format == 'Excel':
                    # Excel格式导出
                    file_path = os.path.join(export_dir, f'租金记录_{today}.xlsx')
                    self.exportToExcel(headers, data, file_path)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'租金记录数据已成功导出到\n{file_path},并已自动打开文件')
                else:
                    # PDF格式导出
                    file_path = os.path.join(export_dir, f'租金记录_{today}.pdf')
                    self.exportToPDF(headers, data, file_path)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'租金记录数据已成功导出到\n{file_path},并已自动打开文件')
            except Exception as e:
                QMessageBox.critical(self, '导出失败', f'导出租金记录数据时发生错误:\n{str(e)}')
    
    def exportToExcel(self, headers, data, file_path):
        # 导出数据到Excel并优化表格样式
        # 导入必要的样式类
        from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
        from openpyxl.utils import get_column_letter
        # 创建DataFrame
        df = pd.DataFrame(data, columns=headers)
        
        # 创建ExcelWriter对象
        with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
            # 将数据写入Excel
            df.to_excel(writer, index=False, sheet_name='租金记录')
            
            # 获取工作表
            worksheet = writer.sheets['租金记录']
            
            # 设置列宽自适应
            for col_idx, col in enumerate(worksheet.columns):
                max_length = 0
                column = col_idx + 1  # 列索引从1开始
                
                # 计算每列的最大宽度
                for cell in col:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                
                # 设置列宽（加一点边距）
                adjusted_width = (max_length + 2) * 1.2
                worksheet.column_dimensions[get_column_letter(column)].width = adjusted_width
            
            # 设置表头样式
            header_font = Font(bold=True, color="FFFFFF")
            header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
            border_style = Border(left=Side(style='thin'), 
                                 right=Side(style='thin'), 
                                 top=Side(style='thin'), 
                                 bottom=Side(style='thin'))
            
            # 应用表头样式
            for cell in worksheet[1]:
                cell.font = header_font
                cell.fill = header_fill
                cell.alignment = Alignment(horizontal="center", vertical="center")
                cell.border = border_style
            
            # 设置数据区域样式
            for row in worksheet.iter_rows(min_row=2, max_row=worksheet.max_row):
                for cell in row:
                    cell.alignment = Alignment(horizontal="center", vertical="center")
                    cell.border = border_style
    
    def exportToPDF(self, headers, data, file_path):
        # 导出数据到PDF并优化页面样式
        from reportlab.pdfbase import pdfmetrics
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.lib.units import inch
        from reportlab.lib.pagesizes import landscape
        
        # 尝试注册多个中文字体,增加成功概率
        font_name = 'Helvetica'
        font_registered = False
        
        # Windows系统常用的中文字体列表
        chinese_fonts = [
            ('SimHei', 'simhei.ttf'),
            ('Microsoft YaHei', 'msyh.ttc'),
            ('Arial Unicode MS', 'arialuni.ttf'),
            ('FangSong', 'simsunb.ttf'),
            ('KaiTi', 'simkai.ttf')
        ]
        
        # 尝试从系统字体目录加载字体
        system_font_paths = [
            'C:/Windows/Fonts/',
            'C:/WINNT/Fonts/',
            os.path.expanduser('~/.fonts/')
        ]
        
        # 尝试注册字体
        for font_family, font_file in chinese_fonts:
            try:
                # 首先尝试直接注册（假设字体在系统路径中）
                pdfmetrics.registerFont(TTFont(font_family, font_file))
                font_name = font_family
                font_registered = True
                break
            except:
                # 尝试从系统字体目录注册
                for font_path in system_font_paths:
                    try:
                        full_font_path = os.path.join(font_path, font_file)
                        if os.path.exists(full_font_path):
                            pdfmetrics.registerFont(TTFont(font_family, full_font_path))
                            font_name = font_family
                            font_registered = True
                            break
                    except:
                        continue
                if font_registered:
                    break
        
        # 准备表格数据并处理长文本
        table_data = [headers] + []
        for row in data:
            new_row = []
            for cell in row:
                # 处理单元格内容,确保能正确显示
                if isinstance(cell, str):
                    # 对于长文本,可以考虑添加换行符或缩短显示
                    new_row.append(cell)
                else:
                    new_row.append(str(cell) if cell is not None else '')
            table_data.append(new_row)
        
        # 计算内容所需的最小宽度,以决定是否需要横向排版
        # 估算每列内容的最大宽度（以字符数为基础）
        column_widths = [0] * len(headers)
        for row in table_data:
            for i, cell in enumerate(row):
                # 假设每个中文字符宽度约为10,英文字符约为5
                char_count = len(cell)
                # 中文字符比例估算
                chinese_chars = sum(1 for c in cell if '\u4e00' <= c <= '\u9fff')
                # 估算列宽需求（像素）
                estimated_width = chinese_chars * 10 + (char_count - chinese_chars) * 5
                column_widths[i] = max(column_widths[i], estimated_width)
        
        # 计算总宽度需求（加上列间距）
        total_width_needed = sum(column_widths) + (len(headers) - 1) * 5
        
        # 设置页面大小和方向
        # 默认使用竖向页面
        pagesize = letter
        page_width = letter[0] - 72  # 减去左右边距
        
        # 如果内容宽度超过页面宽度,切换为横向排版
        if total_width_needed > page_width:
            pagesize = landscape(letter)
            page_width = letter[1] - 72  # 横向时宽度变为原高度减去边距
        
        # 创建文档,减小页边距以增加内容区域
        doc = SimpleDocTemplate(file_path, pagesize=pagesize,
                               rightMargin=36, leftMargin=36,
                               topMargin=36, bottomMargin=36)
        elements = []
        
        # 添加标题
        styles = getSampleStyleSheet()
        # 如果注册了中文字体,更新标题样式
        if font_registered:
            styles['Title'].fontName = font_name
            styles['Normal'].fontName = font_name
        
        title = Paragraph("租金记录数据报表", styles['Title'])
        elements.append(title)
        elements.append(Spacer(1, 12))
        
        # 添加报表生成日期
        today = datetime.now().strftime("%Y%m%d_%H%M%S")
        date_text = Paragraph(f"报表生成日期:{today}", styles['Normal'])
        elements.append(date_text)
        elements.append(Spacer(1, 24))
        
        # 计算页面宽度和表格宽度
        current_page_width = pagesize[0] - doc.leftMargin - doc.rightMargin
        table_width = current_page_width
        
        # 动态计算每列的宽度,根据列的数量平均分配
        col_widths = [table_width / len(headers) for _ in headers]
        
        # 创建表格,指定列宽
        table = Table(table_data, colWidths=col_widths)
        
        # 设置表格样式
        table_style = TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#4F81BD')),  # 深蓝色表头背景
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # 白色表头文字
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 居中对齐
            ('FONTNAME', (0, 0), (-1, 0), font_name),  # 表头字体
            ('FONTSIZE', (0, 0), (-1, -1), 10),  # 设置字体大小,确保内容能显示
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),  # 表头下内边距
            ('TOPPADDING', (0, 0), (-1, 0), 12),  # 表头上内边距
            ('GRID', (0, 0), (-1, -1), 1, colors.black),  # 表格边框
            ('FONTNAME', (0, 1), (-1, -1), font_name),  # 数据字体
            ('BACKGROUND', (0, 1), (-1, -1), colors.white),  # 数据行背景色
            ('BACKGROUND', (0, 2), (-1, -1), colors.HexColor('#F2F2F2')),  # 交替行背景色
            ('WORDWRAP', (0, 0), (-1, -1), 1),  # 启用自动换行
        ])
        table.setStyle(table_style)
        
        # 添加表格到元素列表
        elements.append(table)
        
        # 添加页脚信息
        elements.append(Spacer(1, 24))
        footer_text = Paragraph("租赁合同管理系统 - 租金记录数据报表", styles['Normal'])
        footer_text.alignment = 1  # 居中对齐
        elements.append(footer_text)
        
        # 构建PDF
        doc.build(elements)
    
    def openFile(self, file_path):
        # 自动打开文件
        try:
            if os.name == 'nt':  # Windows系统
                os.startfile(file_path)
            else:  # macOS或Linux系统
                import subprocess
                opener = 'open' if sys.platform == 'darwin' else 'xdg-open'
                subprocess.call([opener, file_path])
        except Exception as e:
            # 如果自动打开失败,不提示用户,让用户手动打开
            pass

# 导出数据对话框
class ExportDataDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('导出数据')
        self.resize(300, 150)
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建格式选择组
        format_group = QGroupBox('选择导出格式')
        format_layout = QVBoxLayout(format_group)
        
        # 创建单选按钮组
        self.format_group = QButtonGroup(self)
        
        # Excel格式单选按钮
        self.excel_radio = QRadioButton('Excel (.xlsx)')
        self.excel_radio.setChecked(True)  # 默认选择Excel格式
        self.format_group.addButton(self.excel_radio)
        format_layout.addWidget(self.excel_radio)
        
        # PDF格式单选按钮
        self.pdf_radio = QRadioButton('PDF (.pdf)')
        self.format_group.addButton(self.pdf_radio)
        format_layout.addWidget(self.pdf_radio)
        
        # 添加格式选择组到主布局
        main_layout.addWidget(format_group)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 确定按钮
        self.ok_button = QPushButton('确定')
        self.ok_button.clicked.connect(self.accept)
        button_layout.addWidget(self.ok_button)
        
        # 取消按钮
        self.cancel_button = QPushButton('取消')
        self.cancel_button.clicked.connect(self.reject)
        button_layout.addWidget(self.cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
    
    def getExportFormat(self):
        # 获取选择的导出格式
        if self.excel_radio.isChecked():
            return 'Excel'
        else:
            return 'PDF'

# 租金记录对话框
class RentRecordDialog(QDialog):
    # 定义一个信号,用于在保存数据时发出
    data_saved = pyqtSignal()
    
    def __init__(self, is_edit=False, rent_data=None):
        super().__init__()
        self.is_edit = is_edit
        self.rent_data = rent_data
        self.initUI()
    
    def initUI(self):
        # 设置窗口标题
        if self.is_edit:
            self.setWindowTitle('编辑租金记录')
        else:
            self.setWindowTitle('添加租金记录')
        
        # 设置窗口大小（增加了100个单位的宽度）
        self.resize(700, 400)
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建表单布局
        form_layout = QFormLayout()
        
        # 合同编号 - 带选择按钮
        contract_layout = QHBoxLayout()
        self.contract_no_edit = QLineEdit()
        self.contract_no_edit.setReadOnly(True)  # 设置合同编号为只读
        select_contract_button = QPushButton('...')
        select_contract_button.setFixedWidth(40)  # 调整宽度以适配新窗口
        select_contract_button.clicked.connect(self.showContractSelectionDialog)
        contract_layout.addWidget(self.contract_no_edit)
        contract_layout.addWidget(select_contract_button)
        
        # 添加房屋编号到合同布局
        house_no_label = QLabel('房屋编号:')
        # 使用全局样式
        contract_layout.addWidget(house_no_label)
        self.house_no_edit = QLineEdit()
        self.house_no_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        contract_layout.addWidget(self.house_no_edit)
        contract_layout.addWidget(QLabel(' '))  # 添加空白标签作为间距
        
        # 添加收款情况文本输入框（只读）
        payment_status_label = QLabel('收款情况:')
        # 使用全局样式
        contract_layout.addWidget(payment_status_label)
        self.payment_status_edit = QLineEdit('未选择')
        self.payment_status_edit.setMinimumWidth(100)  # 调整宽度以适配新窗口
        self.payment_status_edit.setReadOnly(True)  # 设置为只读不可编辑
        self.contract_no_edit.textChanged.connect(self.updatePaymentStatus)
        contract_layout.addWidget(self.payment_status_edit)
        
        # 合同编号
        contract_no_label = QLabel('合同编号:')
        # 使用全局样式
        form_layout.addRow(contract_no_label, contract_layout)
        
        # 合同起止期间
        self.contract_period_edit = QLineEdit()
        self.contract_period_edit.setReadOnly(True)  # 设置为只读,通过合同编号填充
        self.contract_no_edit.textChanged.connect(self.updateContractPeriod)
        # 合同起止期间
        contract_period_label = QLabel('合同起止期间:')
        # 使用全局样式
        form_layout.addRow(contract_period_label, self.contract_period_edit)
        
        # 创建水平布局来放置承租方和承租人
        party_layout = QHBoxLayout()
        
        # 承租方（乙方）
        self.lessee_edit = QLineEdit()
        self.lessee_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        lessee_label = QLabel('承租方（乙方）:')
        # 使用全局样式
        party_layout.addWidget(lessee_label)
        party_layout.addWidget(self.lessee_edit)
        party_layout.addStretch()
        
        # 承租人
        self.tenant_edit = QLineEdit()
        self.tenant_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        tenant_label = QLabel('承租人:')
        # 使用全局样式
        party_layout.addWidget(tenant_label)
        party_layout.addWidget(self.tenant_edit)
        
        # 添加水平布局到表单布局
        form_layout.addRow(party_layout)
        
        # 创建水平布局来放置租金支付方式和月租金
        payment_layout = QHBoxLayout()
        
        # 租金支付方式
        self.payment_method_edit = QLineEdit()
        self.payment_method_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        payment_method_label = QLabel('租金支付方式:')
        # 使用全局样式
        payment_layout.addWidget(payment_method_label)
        payment_layout.addWidget(self.payment_method_edit)
        payment_layout.addStretch()
        
        # 月租金
        self.monthly_rent_edit = QLineEdit()
        self.monthly_rent_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        monthly_rent_label = QLabel('月租金:')
        # 使用全局样式
        payment_layout.addWidget(monthly_rent_label)
        payment_layout.addWidget(self.monthly_rent_edit)
        payment_layout.addStretch()
        
        # 季租金
        self.quarterly_rent_edit = QLineEdit()
        self.quarterly_rent_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        quarterly_rent_label = QLabel('季租金:')
        # 使用全局样式
        payment_layout.addWidget(quarterly_rent_label)
        payment_layout.addWidget(self.quarterly_rent_edit)
        payment_layout.addStretch()
        
        # 年租金
        self.yearly_rent_edit = QLineEdit()
        self.yearly_rent_edit.setReadOnly(True)  # 设置为只读,只能通过选择合同填充
        yearly_rent_label = QLabel('年租金:')
        # 使用全局样式
        payment_layout.addWidget(yearly_rent_label)
        payment_layout.addWidget(self.yearly_rent_edit)
        
        # 添加水平布局到表单布局
        form_layout.addRow(payment_layout)
        
        # 创建水平布局来放置最近收款所属期间和应收总租金
        period_layout = QHBoxLayout()
        
        # 最近收款所属期间
        last_period_label = QLabel('最近收款所属期间:')
        # 使用全局样式
        period_layout.addWidget(last_period_label)
        self.last_period_edit = QLineEdit()
        self.last_period_edit.setReadOnly(True)  # 设置为只读,通过合同编号填充
        self.last_period_edit.setMinimumWidth(208)  # 调整宽度为原宽度的130%（增加30%）
        self.contract_no_edit.textChanged.connect(self.updateLastPeriod)
        period_layout.addWidget(self.last_period_edit)
        period_layout.addStretch()
        
        # 应收总租金
        total_rent_label = QLabel('应收总租金:')
        # 使用全局样式
        period_layout.addWidget(total_rent_label)
        self.total_rent_edit = QLineEdit()
        self.total_rent_edit.setReadOnly(True)  # 设置为只读,通过合同编号填充
        self.total_rent_edit.setMinimumWidth(100)  # 调整宽度以适配新窗口
        self.contract_no_edit.textChanged.connect(self.updateTotalRent)
        period_layout.addWidget(self.total_rent_edit)
        
        # 添加水平布局到表单布局
        form_layout.addRow(period_layout)
        
        # 创建水平布局用于收款日期和收款金额
        payment_layout = QHBoxLayout()
        receipt_date_label = QLabel('收款日期:')
        # 使用全局样式
        payment_layout.addWidget(receipt_date_label)
        self.receipt_date_edit = QDateEdit()
        self.receipt_date_edit.setCalendarPopup(True)
        self.receipt_date_edit.setDate(QDate.currentDate())
        self.receipt_date_edit.setMinimumWidth(150)  # 调整宽度以适配新窗口
        payment_layout.addWidget(self.receipt_date_edit)
        
        # 添加收取第和月季年下拉框
        period_num_label = QLabel('收取第:')
        # 使用全局样式
        payment_layout.addWidget(period_num_label)
        self.period_number_combo = QComboBox()
        period_number_options = ['全年', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
        self.period_number_combo.addItems(period_number_options)
        # 默认值设置为"全年",索引为0
        self.period_number_combo.setCurrentIndex(0)
        self.period_number_combo.setMinimumWidth(80)
        # 设置为可编辑模式,支持用户手动输入
        self.period_number_combo.setEditable(True)
        payment_layout.addWidget(self.period_number_combo)
        
        payment_layout.addWidget(QLabel(''))  # 空白标签
        self.period_type_combo = QComboBox()
        period_type_options = ['月', '季']
        self.period_type_combo.addItems(period_type_options)
        # 默认值设置为"季",索引为1
        self.period_type_combo.setCurrentIndex(1)
        self.period_type_combo.setMinimumWidth(60)
        payment_layout.addWidget(self.period_type_combo)
        rent_label = QLabel('租金')
        # 使用全局样式
        payment_layout.addWidget(rent_label)
        
        payment_layout.addStretch()
        amount_label = QLabel('收款金额:')
        # 使用全局样式
        payment_layout.addWidget(amount_label)
        self.amount_edit = QDoubleSpinBox()
        self.amount_edit.setRange(0.0, 999999.99)
        self.amount_edit.setDecimals(2)
        self.amount_edit.setValue(0.00)
        self.amount_edit.setMinimumWidth(120)  # 调整宽度以适配新窗口
        payment_layout.addWidget(self.amount_edit)
        form_layout.addRow(payment_layout)
        
        # 创建水平布局用于所属期间开始日期和截止日期
        period_dates_layout = QHBoxLayout()
        period_start_label = QLabel('所属期间开始日期:')
        # 使用全局样式
        period_dates_layout.addWidget(period_start_label)
        self.period_start_edit = QDateEdit()
        self.period_start_edit.setCalendarPopup(True)
        self.period_start_edit.setDate(QDate.currentDate())
        self.period_start_edit.setMinimumWidth(150)  # 调整宽度以适配新窗口
        period_dates_layout.addWidget(self.period_start_edit)
        period_dates_layout.addStretch()
        period_end_label = QLabel('所属期间截止日期:')
        # 使用全局样式
        period_dates_layout.addWidget(period_end_label)
        self.period_end_edit = QDateEdit()
        self.period_end_edit.setCalendarPopup(True)
        self.period_end_edit.setDate(QDate.currentDate().addMonths(1).addDays(-1))
        self.period_end_edit.setMinimumWidth(150)  # 调整宽度以适配新窗口
        period_dates_layout.addWidget(self.period_end_edit)
        form_layout.addRow(period_dates_layout)
        
        # 创建水平布局用于收款账户和发票收据开具日期
        account_layout = QHBoxLayout()
        account_label = QLabel('收款账户:')
        # 使用全局样式
        account_layout.addWidget(account_label)
        self.account_edit = QComboBox()
        account_options = ['基本账户', '微信', '现金', '支付宝', '其它']
        self.account_edit.addItems(account_options)
        self.account_edit.setMinimumWidth(120)  # 调整宽度以适配新窗口
        account_layout.addWidget(self.account_edit)
        account_layout.addStretch()
        invoice_date_label = QLabel('发票收据开具日期:')
        # 使用全局样式
        account_layout.addWidget(invoice_date_label)
        self.invoice_date_edit = QDateEdit()
        self.invoice_date_edit.setCalendarPopup(True)
        self.invoice_date_edit.setDate(QDate.currentDate())
        self.invoice_date_edit.setMinimumWidth(150)  # 调整宽度以适配新窗口
        account_layout.addWidget(self.invoice_date_edit)
        form_layout.addRow(account_layout)
        
        # 说明
        self.description_edit = QTextEdit()
        self.description_edit.setMinimumHeight(80)  # 调整高度以适配新窗口
        description_label = QLabel('说明:')
        # 使用全局样式
        form_layout.addRow(description_label, self.description_edit)
        
        # 为相关字段添加信号-槽连接,实现说明自动填充和日期计算
        self.receipt_date_edit.dateChanged.connect(self.updateDescription)
        self.period_number_combo.currentTextChanged.connect(self.updateDescription)
        self.period_type_combo.currentTextChanged.connect(self.updateDescription)
        self.amount_edit.valueChanged.connect(self.updateDescription)
        # 连接收款金额变化信号到自动更新收款情况的方法
        self.amount_edit.valueChanged.connect(self.autoUpdatePaymentStatus)
        
        # 连接信号以自动计算所属期间日期
        self.period_number_combo.currentTextChanged.connect(self.updatePeriodDates)
        self.period_type_combo.currentTextChanged.connect(self.updatePeriodDates)
        self.contract_no_edit.textChanged.connect(self.updatePeriodDates)  # 合同编号变更时也自动计算所属期间
        
        # 添加表单布局到主布局
        main_layout.addLayout(form_layout)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 保存按钮
        save_button = QPushButton('保存')
        save_button.clicked.connect(self.accept)
        button_layout.addWidget(save_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(self.reject)
        button_layout.addWidget(cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 如果是编辑模式,填充数据
        if self.is_edit and self.rent_data:
            self.fillRentData()
    
    def fillRentData(self):
        """
        填充租金记录数据到编辑窗口的各个输入控件中
        
        功能: 当打开编辑租金记录窗口时,根据选中的租金记录信息,自动填充所有相关字段
        
        参数:
            无,使用类中存储的self.rent_data数据
        
        实现步骤:
            1. 填充基本合同信息（合同编号、承租方、房屋编号等）
            2. 填充租金支付相关信息（收款日期、金额、账户等）
            3. 填充所属期间信息
        """
        # rent_data 的结构: (id, contract_no, lessee, tenant, receipt_date, amount, period_start, period_end, account, invoice_date, description, house_no, payment_method, monthly_rent)
        
        # 填充合同基本信息
        if self.rent_data[1]:
            self.contract_no_edit.setText(self.rent_data[1])
        
        if self.rent_data[2]:
            self.lessee_edit.setText(self.rent_data[2])
        
        if len(self.rent_data) > 11 and self.rent_data[11]:
            self.house_no_edit.setText(self.rent_data[11])
        
        if self.rent_data[3]:
            self.tenant_edit.setText(self.rent_data[3])
        
        if len(self.rent_data) > 12 and self.rent_data[12]:
            self.payment_method_edit.setText(self.rent_data[12])
        
        if len(self.rent_data) > 13 and self.rent_data[13]:
            try:
                # 确保是数字格式再设置
                self.monthly_rent_edit.setText(f"{float(self.rent_data[13]):.2f}")
            except ValueError:
                self.monthly_rent_edit.setText(self.rent_data[13])
        
        # 填充收款情况（如果rent_data中包含该信息）
        if len(self.rent_data) > 14 and self.rent_data[14]:
            self.payment_status_edit.setText(self.rent_data[14])
            self.payment_status_edit.setStyleSheet("color: red;")
        
        # 填充合同起止期间字段（使用合同的租赁开始日期和截止日期组合）
        if len(self.rent_data) > 15 and len(self.rent_data) > 16:
            start_date = self.rent_data[15] if self.rent_data[15] else ''
            end_date = self.rent_data[16] if self.rent_data[16] else ''
            if start_date and end_date:
                # 组合格式为：开始日期 - 截止日期
                self.contract_period_edit.setText(f"{start_date} - {end_date}")
            elif start_date:
                self.contract_period_edit.setText(f"{start_date} - ")
            elif end_date:
                self.contract_period_edit.setText(f" - {end_date}")
        
        # 计算季度租金和年度租金
        try:
            if len(self.rent_data) > 13 and self.rent_data[13]:
                monthly_rent = float(self.rent_data[13])
                # 设置季租金（月租金 * 3）
                quarterly_rent = monthly_rent * 3
                self.quarterly_rent_edit.setText(f"{quarterly_rent:.2f}")
                
                # 设置年租金（月租金 * 12）
                yearly_rent = monthly_rent * 12
                self.yearly_rent_edit.setText(f"{yearly_rent:.2f}")
        except ValueError:
            pass
        
        # 填充收款相关信息
        if self.rent_data[4]:
            receipt_date = QDate.fromString(self.rent_data[4], 'yyyy-MM-dd')
            self.receipt_date_edit.setDate(receipt_date)
        
        if self.rent_data[5]:
            self.amount_edit.setValue(float(self.rent_data[5]))
        
        # 填充所属期间信息
        if self.rent_data[6]:
            period_start = QDate.fromString(self.rent_data[6], 'yyyy-MM-dd')
            self.period_start_edit.setDate(period_start)
        
        if self.rent_data[7]:
            period_end = QDate.fromString(self.rent_data[7], 'yyyy-MM-dd')
            self.period_end_edit.setDate(period_end)
        
        # 填充账户信息
        if self.rent_data[8]:
            account_text = self.rent_data[8]
            # 查找账户文本对应的索引
            index = self.account_edit.findText(account_text)
            if index >= 0:
                self.account_edit.setCurrentIndex(index)
            else:
                # 如果找不到,就添加到下拉框并选中
                self.account_edit.addItem(account_text)
                self.account_edit.setCurrentText(account_text)
        
        # 填充发票日期
        if self.rent_data[9]:
            invoice_date = QDate.fromString(self.rent_data[9], 'yyyy-MM-dd')
            self.invoice_date_edit.setDate(invoice_date)
        
        # 填充说明
        if self.rent_data[10]:
            self.description_edit.setText(self.rent_data[10])
    
    def updatePaymentStatus(self):
        # 根据合同编号更新收款情况文本输入框
        contract_no = self.contract_no_edit.text()
        if not contract_no:
            self.payment_status_edit.setText('未选择')
            # 启用所有字段
            self.setFieldsEditable(True)
            return
        
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询年租金总额
            cursor.execute("SELECT annual_rent FROM contracts WHERE contract_no = ?", (contract_no,))
            result = cursor.fetchone()
            if not result:
                self.payment_status_edit.setText('合同不存在')
                self.setFieldsEditable(True)
                conn.close()
                return
            
            annual_rent_value = float(result[0]) if result[0] is not None else 0
            
            # 查询已收总租金
            cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
            result = cursor.fetchone()
            received_rent = float(result[0]) if result[0] is not None else 0
            received_rent = round(received_rent)  # 四舍五入,保留整数
            
            # 计算剩余租金
            remaining_rent = annual_rent_value - received_rent
            remaining_rent = round(remaining_rent)  # 四舍五入,保留整数
            
            # 判断收款情况
            if remaining_rent != 0:
                payment_status = "未结清"
                # 启用所有字段
                self.setFieldsEditable(True)
            else:
                payment_status = "已结清"
                # 如果是编辑模式且收款情况为已结清,锁定所有字段
                if self.is_edit:
                    self.setFieldsEditable(False)
                else:
                    self.setFieldsEditable(True)
            
            # 显示收款情况并设置字体颜色为红色
            self.payment_status_edit.setText(payment_status)
            self.payment_status_edit.setStyleSheet("color: red;")
            
        except Exception as e:
            self.payment_status_edit.setText('查询出错')
            self.setFieldsEditable(True)
        finally:
            if 'conn' in locals() and conn:
                conn.close()
                
    def updateLastPeriod(self):
        # 根据合同编号更新最近收款所属期间
        contract_no = self.contract_no_edit.text()
        if not contract_no:
            self.last_period_edit.setText('')
            return
        
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询该合同的最近收款记录（按收款日期降序排列）
            cursor.execute(
                "SELECT period_start, period_end FROM rent_records WHERE contract_no = ? ORDER BY receipt_date DESC LIMIT 1", 
                (contract_no,)
            )
            result = cursor.fetchone()
            
            if result and result[0] and result[1]:
                # 格式化显示最近收款所属期间
                period_text = f"{result[0]} 至 {result[1]}"
                self.last_period_edit.setText(period_text)
            else:
                # 没有找到收款记录
                self.last_period_edit.setText('暂无收款记录')
                
        except Exception as e:
            # 查询出错时清空显示
            self.last_period_edit.setText('查询出错')
        finally:
            if 'conn' in locals() and conn:
                conn.close()
                
    def updateContractPeriod(self):
        # 根据合同编号更新合同起止期间
        contract_no = self.contract_no_edit.text()
        if not contract_no:
            self.contract_period_edit.setText('')
            return
        
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询该合同的租赁开始日期和租赁截止日期
            cursor.execute(
                "SELECT start_date, end_date FROM contracts WHERE contract_no = ?", 
                (contract_no,)
            )
            result = cursor.fetchone()
            
            if result and result[0] and result[1]:
                # 格式化显示合同起止期间
                period_text = f"{result[0]} 至 {result[1]}"
                self.contract_period_edit.setText(period_text)
            else:
                # 没有找到合同信息或日期为空
                self.contract_period_edit.setText('暂无合同日期信息')
        except Exception as e:
            # 查询出错时显示错误信息
            self.total_rent_edit.setText('查询出错')
        finally:
            if 'conn' in locals() and conn:
                conn.close()
                
    def updateTotalRent(self):
        # 根据合同编号更新应收总租金余额（年租金总额减去已收租金总额）
        contract_no = self.contract_no_edit.text()
        if not contract_no:
            self.total_rent_edit.setText('')
            return
        
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询该合同的年租金总额
            cursor.execute(
                "SELECT annual_rent FROM contracts WHERE contract_no = ?", 
                (contract_no,)
            )
            result = cursor.fetchone()
            
            if not result:
                self.total_rent_edit.setText('合同不存在')
                conn.close()
                return
            
            annual_rent_value = float(result[0]) if result[0] is not None else 0
            
            # 查询已收总租金
            cursor.execute("SELECT SUM(amount) FROM rent_records WHERE contract_no = ?", (contract_no,))
            result = cursor.fetchone()
            received_rent = float(result[0]) if result[0] is not None else 0
            
            # 计算剩余租金（应收总租金余额）
            remaining_rent = annual_rent_value - received_rent
            
            # 格式化显示应收总租金余额（四舍五入保留整数）
            self.total_rent_edit.setText(f"{round(remaining_rent):.0f}")
        except Exception as e:
            # 查询出错时显示错误信息
            self.total_rent_edit.setText('查询出错')
        finally:
            if 'conn' in locals() and conn:
                conn.close()
                
    def autoUpdatePaymentStatus(self):
        """
        根据收款金额和应收总租金自动更新收款情况
        
        功能: 当收款金额字段的值发生变化时,自动计算并更新收款情况字段
        1. 当收款金额等于应收总租金时,设置收款情况为"已结清"
        2. 当收款金额小于应收总租金时,设置收款情况为"未结清"
        """
        try:
            # 获取收款金额
            amount = self.amount_edit.value()
            
            # 获取应收总租金文本并转换为数字
            total_rent_text = self.total_rent_edit.text()
            # 尝试从文本中提取数字
            total_rent_match = re.search(r'\d+(\.\d+)?', total_rent_text)
            if total_rent_match:
                total_rent = float(total_rent_match.group())
            else:
                # 如果无法提取数字,尝试直接转换
                try:
                    total_rent = float(total_rent_text)
                except ValueError:
                    # 如果无法转换,不更新收款情况
                    return
            
            # 根据收款金额和应收总租金的关系更新收款情况
            if amount >= total_rent:
                self.payment_status_edit.setText("已结清")
            else:
                self.payment_status_edit.setText("未结清")
            
            # 设置字体颜色为红色
            self.payment_status_edit.setStyleSheet("color: red;")
            
        except Exception as e:
            # 出错时不更新收款情况
            pass
                
    def setFieldsEditable(self, editable):
        # 设置所有字段的可编辑状态
        # 只读字段保持不变

        
        # 可编辑字段根据editable参数设置
        self.receipt_date_edit.setEnabled(editable)
        self.amount_edit.setEnabled(editable)
        self.period_start_edit.setEnabled(editable)
        self.period_end_edit.setEnabled(editable)
        self.account_edit.setEnabled(editable)
        self.invoice_date_edit.setEnabled(editable)
        self.description_edit.setEnabled(editable)
        
        # 查找保存按钮并设置状态
        for child in self.findChildren(QPushButton):
            if child.text() == '保存':
                child.setEnabled(editable)
    
    def updateDescription(self):
        # 根据收租年月和月季年自动更新说明输入框
        period_number = self.period_number_combo.currentText()
        period_type = self.period_type_combo.currentText()
        
        # 根据用户要求的规则生成说明文本
        if period_number == '全年':
            description_text = f'{period_number}租金'
        else:
            description_text = f'第{period_number}{period_type}租金'
        
        # 更新说明输入框
        self.description_edit.setPlainText(description_text)
        
    def updatePeriodDates(self):
        """当收租年月和月季年字段的值发生变更时,自动计算并更新所属期间开始日期与所属期间截止日期的值"""
        try:
            period_number = self.period_number_combo.currentText()
            period_type = self.period_type_combo.currentText()
            last_period = self.last_period_edit.text()
            contract_period = self.contract_period_edit.text()
            
            # 确保合同信息已加载
            if not contract_period or contract_period == '暂无合同日期信息':
                return
            
            # 解析合同起止期间
            contract_dates = contract_period.split(' 至 ')
            if len(contract_dates) != 2:
                return
            
            contract_start_date = QDate.fromString(contract_dates[0], 'yyyy-MM-dd')
            contract_end_date = QDate.fromString(contract_dates[1], 'yyyy-MM-dd')
            
            # 规则1: 若收租年月的值为"全年",则使用合同起止期间
            if period_number == '全年':
                self.period_start_edit.setDate(contract_start_date)
                self.period_end_edit.setDate(contract_end_date)
                return
            
            # 规则2-5: 收租年月不为"全年"
            has_last_record = last_period != '暂无收款记录' and last_period != '' and last_period != '查询出错'
            
            if not has_last_record:
                # 规则2: 月
                if period_type == '月':
                    self.period_start_edit.setDate(contract_start_date)
                    # 计算截止日期:合同开始日期的月份值加1,日期值减1
                    period_end = contract_start_date.addMonths(1).addDays(-1)
                    self.period_end_edit.setDate(period_end)
                # 规则3: 季
                elif period_type == '季':
                    self.period_start_edit.setDate(contract_start_date)
                    # 计算截止日期:合同开始日期的月份值加3,日期值减1
                    period_end = contract_start_date.addMonths(3).addDays(-1)
                    self.period_end_edit.setDate(period_end)
            else:
                # 解析最近收款所属期间
                last_dates = last_period.split(' 至 ')
                if len(last_dates) != 2:
                    return
                
                last_period_start = QDate.fromString(last_dates[0], 'yyyy-MM-dd')
                last_period_end = QDate.fromString(last_dates[1], 'yyyy-MM-dd')
                
                # 规则4: 月
                if period_type == '月':
                    # 开始日期:最近收款截止日期+1
                    self.period_start_edit.setDate(last_period_end.addDays(1))
                    # 计算截止日期:开始日期的月份值加1,日期值减1
                    period_end = last_period_end.addDays(1).addMonths(1).addDays(-1)
                    self.period_end_edit.setDate(period_end)
                # 规则5: 季
                elif period_type == '季':
                    # 开始日期:最近收款截止日期+1
                    self.period_start_edit.setDate(last_period_end.addDays(1))
                    # 计算截止日期:开始日期的月份值加3,日期值减1
                    period_end = last_period_end.addDays(1).addMonths(3).addDays(-1)
                    self.period_end_edit.setDate(period_end)
        except Exception as e:
            # 发生错误时,不影响用户操作,静默处理
            pass
        
    def showContractSelectionDialog(self):
        # 创建合同选择对话框
        dialog = QDialog(self)
        dialog.setWindowTitle('选择合同')
        dialog.resize(900, 400)
        
        # 创建主布局
        main_layout = QVBoxLayout(dialog)
        
        # 创建搜索框
        search_layout = QHBoxLayout()
        search_label = QLabel('搜索:')
        search_input = QLineEdit()
        search_input.setPlaceholderText('输入关键词搜索所有非数字字段（合同编号、承租方、房屋位置等）')
        search_button = QPushButton('搜索')
        reset_button = QPushButton('重置')
        
        search_layout.addWidget(search_label)
        search_layout.addWidget(search_input)
        search_layout.addWidget(search_button)
        search_layout.addWidget(reset_button)
        main_layout.addLayout(search_layout)
        
        # 创建合同表格
        contract_table = QTableWidget()
        contract_table.setColumnCount(11)  # 增加一列用于显示收款情况
        contract_table.setHorizontalHeaderLabels(['合同编号', '房屋编号', '承租方（乙方）', '承租人', '租金支付方式', '月租金', '季度租金', '年租金总额', '租赁开始日期', '租赁截止日期', '收款情况'])
        contract_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        contract_table.setEditTriggers(QTableWidget.NoEditTriggers)
        contract_table.setSelectionBehavior(QTableWidget.SelectRows)
        
        # 加载合同数据
        try:
            # 连接数据库
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询合同数据,筛选收款情况为"未结清"的记录
            # 按房屋编号升序排序
            cursor.execute("SELECT contract_no, house_no, lessee, tenant, payment_method, monthly_rent, start_date, end_date, payment_status FROM contracts WHERE payment_status = '未结清' ORDER BY house_no ASC")
            contracts = cursor.fetchall()
            
            # 填充表格
            contract_table.setRowCount(len(contracts))
            for row_idx, contract in enumerate(contracts):
                # 处理前6列（原始数据）
                for col_idx in range(6):
                    if col_idx < len(contract):
                        value = contract[col_idx]
                        # 格式化月租金显示
                        if col_idx == 5:  # 月租金列
                            item = QTableWidgetItem(f'{float(value):.2f}' if value is not None else '0.00')
                        else:
                            item = QTableWidgetItem(str(value) if value is not None else '')
                        item.setTextAlignment(Qt.AlignCenter)
                        contract_table.setItem(row_idx, col_idx, item)
                    else:
                        item = QTableWidgetItem('')
                        item.setTextAlignment(Qt.AlignCenter)
                        contract_table.setItem(row_idx, col_idx, item)
                
                # 处理季度租金列（第7列）
                monthly_rent = float(contract[5]) if contract[5] is not None else 0.0
                quarterly_rent = monthly_rent * 3
                quarterly_rent_item = QTableWidgetItem(f'{quarterly_rent:.0f}')
                quarterly_rent_item.setTextAlignment(Qt.AlignCenter)
                contract_table.setItem(row_idx, 6, quarterly_rent_item)
                
                # 处理年租金总额列（第8列）
                yearly_rent = monthly_rent * 12
                yearly_rent_item = QTableWidgetItem(f'{yearly_rent:.0f}')
                yearly_rent_item.setTextAlignment(Qt.AlignCenter)
                contract_table.setItem(row_idx, 7, yearly_rent_item)
                
                # 处理新增的租赁开始日期列（第9列）
                if len(contract) > 6 and contract[6] is not None:
                    start_date_item = QTableWidgetItem(contract[6])
                    start_date_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 8, start_date_item)
                else:
                    start_date_item = QTableWidgetItem('')
                    start_date_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 8, start_date_item)
                
                # 处理新增的租赁截止日期列（第10列）
                if len(contract) > 7 and contract[7] is not None:
                    end_date_item = QTableWidgetItem(contract[7])
                    end_date_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 9, end_date_item)
                else:
                    end_date_item = QTableWidgetItem('')
                    end_date_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 9, end_date_item)
                
                # 处理收款情况列（第11列）
                if len(contract) > 8 and contract[8] is not None:
                    payment_status_item = QTableWidgetItem(contract[8])
                    payment_status_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 10, payment_status_item)
                else:
                    payment_status_item = QTableWidgetItem('')
                    payment_status_item.setTextAlignment(Qt.AlignCenter)
                    contract_table.setItem(row_idx, 10, payment_status_item)
            
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载合同数据时发生错误:\n{str(e)}')
        
        # 搜索功能
        def search_contracts():
            search_text = search_input.text().lower()
            for row_idx in range(contract_table.rowCount()):
                match = False
                for col_idx in range(contract_table.columnCount()):
                    item = contract_table.item(row_idx, col_idx)
                    if item and search_text in item.text().lower():
                        match = True
                        break
                contract_table.setRowHidden(row_idx, not match)
        
        # 重置搜索功能
        def reset_contracts_search():
            search_input.clear()
            search_contracts()
        
        search_button.clicked.connect(search_contracts)
        search_input.returnPressed.connect(search_contracts)
        reset_button.clicked.connect(reset_contracts_search)
        
        # 双击选择
        def select_contract(row, col):
            contract_no = contract_table.item(row, 0).text()
            house_no = contract_table.item(row, 1).text()
            lessee = contract_table.item(row, 2).text()
            tenant = contract_table.item(row, 3).text()
            payment_method = contract_table.item(row, 4).text()
            monthly_rent = contract_table.item(row, 5).text()
            
            # 填充到表单
            self.contract_no_edit.setText(contract_no)
            self.house_no_edit.setText(house_no)
            self.lessee_edit.setText(lessee)
            self.tenant_edit.setText(tenant)
            self.payment_method_edit.setText(payment_method)
            self.monthly_rent_edit.setText(monthly_rent)
            # 填充季租金和年租金
            quarterly_rent = contract_table.item(row, 6).text()
            yearly_rent = contract_table.item(row, 7).text()
            self.quarterly_rent_edit.setText(quarterly_rent)
            self.yearly_rent_edit.setText(yearly_rent)
            
            # 计算并设置应收总租金余额
            self.updateTotalRent()
            
            dialog.accept()
        
        contract_table.cellDoubleClicked.connect(select_contract)
        
        # 添加表格到布局
        main_layout.addWidget(contract_table)
        
        # 创建按钮区域
        button_layout = QHBoxLayout()
        
        # 确定按钮
        ok_button = QPushButton('确定')
        ok_button.clicked.connect(lambda: dialog.accept())
        button_layout.addWidget(ok_button)
        
        # 取消按钮
        cancel_button = QPushButton('取消')
        cancel_button.clicked.connect(lambda: dialog.reject())
        button_layout.addWidget(cancel_button)
        
        # 添加按钮区域到主布局
        main_layout.addLayout(button_layout)
        
        # 执行对话框
        dialog.exec_()
        
    def getRentData(self):
        # 获取租金记录数据
        # 直接从文本输入框获取收款情况值
        payment_status = self.payment_status_edit.text().strip()
        # 标准化收款情况值
        if payment_status in ['已结清', '未结清']:
            payment_status = payment_status
        else:
            payment_status = '未结清'  # 默认值
            
        rent_data = {
            'contract_no': self.contract_no_edit.text(),
            'house_no': self.house_no_edit.text(),
            'lessee': self.lessee_edit.text(),
            'tenant': self.tenant_edit.text(),
            'payment_method': self.payment_method_edit.text(),
            'monthly_rent': self.monthly_rent_edit.text(),
            'receipt_date': self.receipt_date_edit.date().toString('yyyy-MM-dd'),
            'amount': self.amount_edit.value(),
            'period_start': self.period_start_edit.date().toString('yyyy-MM-dd'),
            'period_end': self.period_end_edit.date().toString('yyyy-MM-dd'),
            'account': self.account_edit.currentText(),
            'invoice_date': self.invoice_date_edit.date().toString('yyyy-MM-dd'),
            'description': self.description_edit.toPlainText(),
            'payment_status': payment_status  # 添加收款情况字段
        }
        
        return rent_data
    
    def clearInputFields(self):
        """清空所有输入框内容"""
        # 不重置合同相关信息,仅清空租金记录相关字段
        self.receipt_date_edit.setDate(QDate.currentDate())
        self.period_number_combo.setCurrentIndex(0)  # 重置为"全年"
        self.period_type_combo.setCurrentIndex(1)  # 重置为"季"
        self.amount_edit.setValue(0.00)
        self.account_edit.setCurrentIndex(0)  # 重置为第一个账户选项
        self.invoice_date_edit.setDate(QDate.currentDate())
        self.description_edit.clear()
        
    def accept(self):
        # 验证数据
        if not self.contract_no_edit.text():
            QMessageBox.warning(self, '警告', '合同编号不能为空!')
            return
        
        if not self.lessee_edit.text():
            QMessageBox.warning(self, '警告', '承租方（乙方）不能为空!')
            return
        
        if self.amount_edit.value() <= 0:
            QMessageBox.warning(self, '警告', '收款金额必须大于0!')
            return
        
        if self.period_start_edit.date() > self.period_end_edit.date():
            QMessageBox.warning(self, '警告', '所属期间开始日期不能晚于所属期间截止日期!')
            return
        
        # 数据验证通过,发出信号
        self.data_saved.emit()
        
        # 关闭对话框
        super().accept()
    
    def updateReminders(self):
        """更新提醒列表 - 增强版,确保可靠的刷新功能和详细的调试信息"""
        # 1. 初始化变量和获取刷新按钮
        refresh_button = None
        for child in self.findChildren(QPushButton):
            if '刷新' in child.text():
                refresh_button = child
                break
          
        # 2. 禁用刷新按钮,防止重复点击
        if refresh_button:
            refresh_button.setEnabled(False)
            # 设置明确的加载状态
            original_text = refresh_button.text()
            refresh_button.setText('刷新中...')
        
        # 3. 清空提醒列表并显示加载提示
        self.reminder_tree.clear()
        loading_item = QTreeWidgetItem(['', '加载中', '正在刷新提醒数据...', '', ''])
        loading_item.setForeground(1, QBrush(QColor('blue')))
        self.reminder_tree.addTopLevelItem(loading_item)
        
        # 强制UI更新,确保用户看到加载状态
        QApplication.processEvents()
        
        # 4. 获取筛选条件
        filter_type = self.filter_combo.currentText()
        
        try:
            # 5. 再次清空,准备加载实际数据
            self.reminder_tree.clear()
            
            # 6. 尝试使用增强版提醒系统 - 采用更可靠的方法查找MainWindow
            try:
                # 多种方式查找MainWindow
                main_window = None
                
                # 方法1:从父组件开始查找
                current_widget = self
                while current_widget and not main_window:
                    if 'MainWindow' in current_widget.__class__.__name__:
                        main_window = current_widget
                        break
                    current_widget = current_widget.parentWidget()
                
                # 方法2:如果方法1失败,尝试使用类方法find_main_window
                if not main_window and hasattr(self, 'find_main_window'):
                    main_window = self.find_main_window(self)
                
                # 方法3:如果方法2失败,尝试全局查找（最后手段）
                if not main_window:
                    for widget in QApplication.topLevelWidgets():
                        if 'MainWindow' in widget.__class__.__name__:
                            main_window = widget
                            break
                
                # 记录找到的MainWindow信息进行调试
                if main_window:
                    # MainWindow实例已找到
                    if hasattr(main_window, 'enhanced_reminder'):
                        # MainWindow包含enhanced_reminder属性
                        # 获取所有筛选条件
                        urgency_filter = self.urgency_combo.currentText()
                        read_status_filter = self.read_status_combo.currentText()
                     
                        # 调用增强版提醒系统的函数来显示提醒
                        show_combined_reminders(
                            main_window.enhanced_reminder, 
                            self.reminder_tree, 
                            filter_type,
                            urgency_filter,
                            read_status_filter
                        )
                    else:
                        # 获取所有筛选条件
                        urgency_filter = self.urgency_combo.currentText()
                        read_status_filter = self.read_status_combo.currentText()
                        
                        # 直接从数据库加载提醒数据
                        self._load_reminders_from_db(filter_type, urgency_filter, read_status_filter)
                else:
                    # 获取所有筛选条件
                    urgency_filter = self.urgency_combo.currentText()
                    read_status_filter = self.read_status_combo.currentText()
                      
                    # 直接从数据库加载提醒数据
                    self._load_reminders_from_db(filter_type, urgency_filter, read_status_filter)
            except Exception as reminder_error:
                # 静默处理提醒系统访问异常
                # 显示提醒系统错误
                error_item = QTreeWidgetItem(['', '加载错误', f'提醒系统访问失败: {str(reminder_error)}', '', ''])
                error_item.setForeground(1, QBrush(QColor('red')))
                self.reminder_tree.addTopLevelItem(error_item)
        except Exception as e:
            # 显示一般错误
            error_item = QTreeWidgetItem(['', '加载错误', f'无法加载提醒数据: {str(e)}', '', ''])
            error_item.setForeground(1, QBrush(QColor('red')))
            self.reminder_tree.addTopLevelItem(error_item)
        
        # 7. 刷新后根据选择状态更新按钮状态
        self.onItemSelectionChanged()
        
        # 8. 恢复刷新按钮状态并提供视觉反馈
        if refresh_button:
            refresh_button.setEnabled(True)
            # 恢复原始文本
            refresh_button.setText(original_text)
            # 简单的视觉反馈
            original_style = refresh_button.styleSheet()
            refresh_button.setStyleSheet("background-color: #4CAF50;")
            
            # 500毫秒后恢复原始样式
            def restore_style():
                if hasattr(refresh_button, 'setStyleSheet'):  # 再次检查按钮是否存在
                    refresh_button.setStyleSheet(original_style)
            
            # 使用更强健的方式设置定时器
            timer = QTimer()
            timer.setSingleShot(True)
            timer.timeout.connect(restore_style)
            timer.start(500)
            
    def _load_reminders_from_db(self, filter_type, urgency_filter=None, read_status_filter=None):
        """直接从数据库加载提醒数据的辅助方法"""
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 设置默认90天以显示更多历史记录
            reminder_days = 90
            
            # 计算起始日期
            from datetime import date, timedelta
            start_date = (date.today() - timedelta(days=reminder_days)).strftime('%Y-%m-%d')
            
            # 构建查询条件,包含dismissed字段用于过滤已关闭的提醒
            query = """
                SELECT id, reminder_type, related_info, reminder_date, is_read, urgency_level, dismissed 
                FROM reminder_logs 
                WHERE reminder_date >= ? AND dismissed = 0
            """
            params = [start_date]
            
            # 添加筛选条件
            if filter_type != '全部提醒':
                query += " AND reminder_type = ?"
                params.append(filter_type)
            
            # 紧急程度筛选
            if urgency_filter is not None and urgency_filter != '全部':
                if urgency_filter == '紧急':
                    query += " AND urgency_level >= 2"
                elif urgency_filter == '普通':
                    query += " AND urgency_level <= 1"
            
            # 已读状态筛选
            if read_status_filter is not None and read_status_filter != '全部':
                if read_status_filter == '未读':
                    query += " AND is_read = 0"
                elif read_status_filter == '已读':
                    query += " AND is_read = 1"
            
            query += " ORDER BY reminder_date DESC, urgency_level DESC"
            
            cursor.execute(query, params)
            logs = cursor.fetchall()
            
            # 提醒记录已从数据库加载
            
            # 填充提醒树
            for log in logs:
                # 创建树项
                status_icon = '🔴'  # 未读
                if log[4]:
                    status_icon = '⚪'  # 已读
                
                item = QTreeWidgetItem([
                    status_icon,
                    log[1],  # 提醒类型
                    log[2],  # 相关信息
                    log[3],  # 日期
                    ''       # 第五列（详情）留空
                ])
                
                # 设置文本颜色
                text_color = None
                if log[1] == '合同逾期':
                    text_color = QColor('red') if log[5] >= 3 else QColor('darkRed')
                elif log[1] == '租金逾期':
                    text_color = QColor('red')
                elif log[1] == '合同到期':
                    text_color = QColor('orange') if log[5] >= 1 else QColor('darkOrange')
                elif log[1] == '租金到期':
                    text_color = QColor('blue')
                elif log[1] == '押金退还':
                    text_color = QColor('green')
                elif log[1] == '水电费结算':
                    text_color = QColor('cyan')
                
                if text_color:
                    item.setForeground(1, QBrush(text_color))
                
                # 如果未读,设置加粗字体
                if not log[4]:
                    font = item.font(0)
                    font.setBold(True)
                    for col in range(5):
                        item.setFont(col, font)
                
                # 设置用户角色数据（用于存储日志ID）
                item.setData(0, Qt.UserRole, log[0])
                self.reminder_tree.addTopLevelItem(item)
            
            # 如果没有提醒,显示提示信息
            if len(logs) == 0:
                no_reminder_item = QTreeWidgetItem(['', '暂无提醒', '当前没有符合条件的提醒记录', '', ''])
                no_reminder_item.setForeground(1, QBrush(QColor('gray')))
                self.reminder_tree.addTopLevelItem(no_reminder_item)
        except Exception as e:
            # 静默处理提醒数据加载异常
            error_item = QTreeWidgetItem(['', '数据库错误', f'无法访问提醒数据库: {str(e)}', '', ''])
            error_item.setForeground(1, QBrush(QColor('red')))
            self.reminder_tree.addTopLevelItem(error_item)
        finally:
            # 确保关闭数据库连接
            if 'conn' in locals():
                DatabaseUtils.close_connection(conn)
        
    def extractDetails(self, reminder_type, related_info):
        """从提醒信息中提取详细内容"""
        if '合同编号' in related_info:
            # 提取合同编号
            contract_no_start = related_info.find('合同编号:') + 5
            contract_no_end = related_info.find(',', contract_no_start)
            if contract_no_end == -1:
                contract_no_end = len(related_info)
            contract_no = related_info[contract_no_start:contract_no_end]
            
            # 提取承租方
            lessee_start = related_info.find('承租方:')
            if lessee_start != -1:
                lessee_start += 4
                lessee_end = related_info.find(',', lessee_start)
                if lessee_end == -1:
                    lessee_end = len(related_info)
                lessee = related_info[lessee_start:lessee_end]
                return f'合同: {contract_no}, 承租方: {lessee}'
            
            return f'合同: {contract_no}'
        
        return related_info
        
    def showUpcomingReminders(self, conn, contract_reminder_days, rent_reminder_days, filter_type):
        """显示即将到期但尚未记录到日志的提醒"""
        today = date.today()
        cursor = conn.cursor()
        
        # 如果筛选条件为全部提醒或合同到期,显示即将到期的合同
        if filter_type in ['全部提醒', '合同到期']:
            # 检查合同到期提醒
            cursor.execute(
                "SELECT contract_no, lessee, end_date, monthly_rent FROM contracts WHERE status = '执行中'"
            )
            contracts = cursor.fetchall()
            
            for contract in contracts:
                contract_no, lessee, end_date_str, monthly_rent = contract
                end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                days_left = (end_date - today).days
                
                # 检查是否在提醒范围内
                if 0 <= days_left <= contract_reminder_days:
                    # 检查是否已经存在于日志中
                    cursor.execute(
                        "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '合同到期' AND related_info LIKE ? AND reminder_date = ?",
                        (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                    )
                    if cursor.fetchone()[0] == 0:
                        # 添加合同到期提醒（即将到期但尚未记录）
                        item = QTreeWidgetItem(['🟡', '合同到期', f'合同编号:{contract_no}\n承租方:{lessee}\n将在{days_left}天后到期', 
                                               today.strftime('%Y-%m-%d'), f'合同: {contract_no}, 承租方: {lessee}'])
                        # 设置为粗体
                        font = item.font(0)
                        font.setBold(True)
                        for col in range(5):
                            item.setFont(col, font)
                        
                        # 根据剩余天数设置颜色
                        if days_left <= 7:
                            item.setForeground(1, QBrush(QColor('red')))
                        elif days_left <= 15:
                            item.setForeground(1, QBrush(QColor('orange')))
                        else:
                            item.setForeground(1, QBrush(QColor('blue')))
                        
                        self.reminder_tree.addTopLevelItem(item)
        
        # 如果筛选条件为全部提醒或租金到期,显示即将到期的租金
        if filter_type in ['全部提醒', '租金到期']:
            # 检查租金到期提醒（完善版本）
            # 获取所有执行中的合同
            cursor.execute(
                "SELECT contract_no, lessee, payment_method, monthly_rent, start_date, end_date FROM contracts WHERE status = '执行中'"
            )
            contracts = cursor.fetchall()
            
            for contract in contracts:
                contract_no, lessee, payment_method, monthly_rent, start_date_str, end_date_str = contract
                
                # 获取该合同的最新租金记录
                cursor.execute(
                    "SELECT MAX(period_end) FROM rent_records WHERE contract_no = ?",
                    (contract_no,)
                )
                last_period_end = cursor.fetchone()[0]
                
                # 计算下一次租金到期日
                next_due_date = None
                
                if last_period_end:
                    # 如果有租金记录,基于最后一个周期结束日计算
                    last_period_end_date = datetime.strptime(last_period_end, '%Y-%m-%d').date()
                    
                    # 根据支付方式计算下一次到期日
                    if payment_method == '月付':
                        next_due_date = last_period_end_date + timedelta(days=30)
                    elif payment_method == '季付':
                        next_due_date = last_period_end_date + timedelta(days=90)
                    elif payment_method == '半年付':
                        next_due_date = last_period_end_date + timedelta(days=180)
                    elif payment_method == '年付':
                        next_due_date = last_period_end_date + timedelta(days=365)
                else:
                    # 如果没有租金记录,基于合同开始日期计算
                    start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
                    next_due_date = start_date
                
                if next_due_date:
                    days_until_due = (next_due_date - today).days
                    
                    # 检查是否在提醒范围内且未超过合同结束日期
                    end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                    if 0 <= days_until_due <= rent_reminder_days and next_due_date <= end_date:
                        # 检查是否已经存在于日志中
                        cursor.execute(
                            "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '租金到期' AND related_info LIKE ? AND reminder_date = ?",
                            (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                        )
                        if cursor.fetchone()[0] == 0:
                            # 添加租金到期提醒（即将到期但尚未记录）
                            item = QTreeWidgetItem(['🟡', '租金到期', 
                                                  f'合同编号:{contract_no}\n承租方:{lessee}\n租金将在{days_until_due}天后到期', 
                                                  today.strftime('%Y-%m-%d'), 
                                                  f'合同: {contract_no}, 承租方: {lessee}'])
                            # 设置为粗体
                            font = item.font(0)
                            font.setBold(True)
                            for col in range(5):
                                item.setFont(col, font)
                            
                            # 设置颜色
                            item.setForeground(1, QBrush(QColor('blue')))
                            
                            self.reminder_tree.addTopLevelItem(item)
        
        # 如果筛选条件为全部提醒或合同逾期,显示已逾期的合同
        if filter_type in ['全部提醒', '合同逾期']:
            # 检查已逾期的合同
            cursor.execute(
                "SELECT contract_no, lessee, end_date FROM contracts WHERE status = '执行中'"
            )
            contracts = cursor.fetchall()
            
            for contract in contracts:
                contract_no, lessee, end_date_str = contract
                end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
                days_overdue = (today - end_date).days
                
                if days_overdue > 0:
                    # 检查是否已经存在于日志中
                    cursor.execute(
                        "SELECT COUNT(*) FROM reminder_logs WHERE reminder_type = '合同逾期' AND related_info LIKE ? AND reminder_date = ?",
                        (f'%{contract_no}%', today.strftime('%Y-%m-%d'))
                    )
                    if cursor.fetchone()[0] == 0:
                        # 添加合同逾期提醒（已逾期但尚未记录）
                        item = QTreeWidgetItem(['🟡', '合同逾期', 
                                              f'合同编号:{contract_no}\n承租方:{lessee}\n已逾期{days_overdue}天', 
                                              today.strftime('%Y-%m-%d'), 
                                              f'合同: {contract_no}, 承租方: {lessee}'])
                        # 设置为粗体
                        font = item.font(0)
                        font.setBold(True)
                        for col in range(5):
                            item.setFont(col, font)
                        
                        # 设置颜色
                        item.setForeground(1, QBrush(QColor('red')))
                        
                        self.reminder_tree.addTopLevelItem(item)
                        
    def markAsRead(self):
        """标记选中的提醒为已读"""
        selected_items = self.reminder_tree.selectedItems()
        if not selected_items:
            QMessageBox.information(self, '提示', '请先选择要标记为已读的提醒')
            return
        
        # 获取选中的日志ID
        log_ids = []
        for item in selected_items:
            log_id = item.data(0, Qt.UserRole)
            if log_id is not None:
                log_ids.append(log_id)
        
        # 更新数据库
        if log_ids:
            try:
                # 直接使用递归查找MainWindow实例（保留但不再使用）
                main_window = self.find_main_window(self)
                # markAsRead - 窗口类型已确认
                
                # 直接操作数据库标记提醒为已读
                # 使用DatabaseUtils获取数据库连接
                from db_utils import DatabaseUtils
                conn = DatabaseUtils.get_connection()
                cursor = conn.cursor()
                placeholders = ','.join(['?'] * len(log_ids))
                cursor.execute(
                    f"UPDATE reminder_logs SET is_read = 1 WHERE id IN ({placeholders})",
                    log_ids
                )
                conn.commit()
                conn.close()
                
                # 更新UI
                self.updateReminders()
                QMessageBox.information(self, '成功', f'已成功标记 {len(log_ids)} 条提醒为已读')
            except Exception as e:
                QMessageBox.warning(self, '操作失败', f'标记提醒为已读时发生错误:{str(e)}')
            
    def deleteSelectedReminders(self):
        """删除选中的提醒记录"""
        selected_items = self.reminder_tree.selectedItems()
        if not selected_items:
            QMessageBox.information(self, '提示', '请先选择要删除的提醒')
            return
        
        # 确认删除
        reply = QMessageBox.question(self, '确认删除', f'确定要删除选中的 {len(selected_items)} 条提醒记录吗?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            # 获取选中的日志ID
            log_ids = []
            for item in selected_items:
                log_id = item.data(0, Qt.UserRole)
                if log_id is not None:
                    log_ids.append(log_id)
            
            # 从数据库删除
            if log_ids:
                # 直接使用递归查找MainWindow实例（保留但不再使用）
                main_window = self.find_main_window(self)
                # deleteSelectedReminders - 窗口类型已确认
                
                # 直接操作数据库删除提醒
                try:
                    # 使用DatabaseUtils获取数据库连接
                    from db_utils import DatabaseUtils
                    conn = DatabaseUtils.get_connection()
                    cursor = conn.cursor()
                    placeholders = ','.join(['?'] * len(log_ids))
                    cursor.execute(
                        f"DELETE FROM reminder_logs WHERE id IN ({placeholders})",
                        log_ids
                    )
                    conn.commit()
                    conn.close()
                    
                    # 更新UI
                    self.updateReminders()
                    QMessageBox.information(self, '成功', f'已成功删除 {len(log_ids)} 条提醒记录')
                except Exception as e:
                    QMessageBox.warning(self, '操作失败', f'删除提醒记录时发生错误:{str(e)}')

# 关于标签页
class BasicInfoTab(QWidget):
    # 导入全局auth_manager
    from user_auth import auth_manager
    def __init__(self):
        super().__init__()
        self.initUI()
    
    def get_software_version(self):
        """从系统设置获取软件版本信息"""
        conn = None
        try:
            # 连接数据库
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 检查system_params表是否存在
            cursor.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'")
            if cursor.fetchone()[0] == 0:
                # 表不存在,使用默认值
                return '1.0.0'
            
            # 查询软件版本
            cursor.execute("SELECT value FROM system_params WHERE key='software_version'")
            result = cursor.fetchone()
            software_version = result[0] if result else '1.0.0'
            
            return software_version
        except Exception as e:
            # 发生任何错误时返回默认值
            return '1.0.0'
        finally:
            # 确保数据库连接关闭
            if conn:
                conn.close()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建标题
        title_label = QLabel('关于系统')
        font = QFont()
        font.setPointSize(14)
        font.setBold(True)
        title_label.setFont(font)
        title_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(title_label)
        
        # 创建信息显示区域
        info_group = QGroupBox('系统信息')
        info_layout = QFormLayout()
        
        # 添加系统信息项 - 从系统设置获取版本信息
        software_version = self.get_software_version()
        version_label = QLabel(f'版本号: {software_version}')
        info_layout.addRow('系统版本:', version_label)
        
        date_label = QLabel(datetime.now().strftime("%Y%m%d_%H%M%S"))
        info_layout.addRow('当前日期:', date_label)
        
        # 数据库信息 - 使用动态配置的数据库路径
        db_path = DatabaseUtils.get_db_path()
        db_label = QLabel(db_path)
        db_label.setToolTip(db_path)
        db_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        info_layout.addRow('数据库路径:', db_label)
        
        # 合同数量信息 - 使用数据库工具类获取连接
        conn = None
        contract_count = 0
        try:
            conn = DatabaseUtils.get_connection()
            if conn:
                cursor = conn.cursor()
                cursor.execute("SELECT COUNT(*) FROM contracts")
                contract_count = cursor.fetchone()[0]
        except Exception as e:
            pass  # 静默处理合同数量获取错误
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
        
        contract_label = QLabel(str(contract_count))
        info_layout.addRow('合同总数:', contract_label)
        
        # 设置表单布局
        info_group.setLayout(info_layout)
        main_layout.addWidget(info_group)
        
        # 创建操作按钮区域
        button_layout = QHBoxLayout()
        
        refresh_button = QPushButton('刷新信息')
        refresh_button.clicked.connect(self.refreshInfo)
        button_layout.addWidget(refresh_button)
        
        # 添加帮助手册按钮
        help_button = QPushButton('帮助手册')
        help_button.clicked.connect(self.openHelpManual)
        button_layout.addWidget(help_button)
        
        about_button = QPushButton('关于系统')
        about_button.clicked.connect(self.showAbout)
        button_layout.addWidget(about_button)
        
        button_layout.addStretch()
        
        main_layout.addLayout(button_layout)
        main_layout.addStretch()
    
    def refreshInfo(self):
        # 刷新信息（简化版本）
        QMessageBox.information(self, '提示', '基础信息已刷新!')
    
    def openHelpManual(self):
        """打开操作手册.html文件"""
        try:
            # 获取当前应用程序目录下的操作手册.html文件路径
            manual_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '操作手册.html')
            
            # 检查文件是否存在
            if os.path.exists(manual_path):
                # 使用系统默认浏览器打开文件
                if sys.platform.startswith('win'):
                    # Windows系统
                    os.startfile(manual_path)
                elif sys.platform.startswith('darwin'):
                    # macOS系统
                    os.system(f'open "{manual_path}"')
                else:
                    # Linux系统
                    os.system(f'xdg-open "{manual_path}"')
            else:
                QMessageBox.warning(self, '文件不存在', '未找到操作手册.html文件！')
        except Exception as e:
            log_error(f'打开帮助手册失败: {str(e)}')
            QMessageBox.error(self, '错误', f'打开帮助手册时发生错误: {str(e)}')
    
    def showAbout(self):
        """显示关于系统对话框,从数据库获取软件信息"""
        try:
            # 连接数据库获取软件信息
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 查询软件信息
            params = {}
            for key in ['software_brand', 'software_name', 'software_version']:
                cursor.execute("SELECT value FROM system_params WHERE key=?", (key,))
                result = cursor.fetchone()
                params[key] = result[0] if result else ''
            
            # 组合软件品牌、名称和版本
            software_info = f"{params['software_brand']}"
            if params['software_name']:
                software_info += f"{params['software_name']}"
            if params['software_version']:
                software_info += f" {params['software_version']}"
            
            # 如果数据库中没有信息,使用默认值
            if not software_info.strip():
                software_info = '租赁合同管理系统 v1.3.0'
                
        except Exception as e:
            # 出错时使用默认值
            software_info = '租赁合同管理系统 v1.3.0'
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
        
        # 显示关于系统对话框
        QMessageBox.about(self, '关于系统', f'{software_info}\n\n一个用于管理租赁合同和租金的系统\n\n功能包括:\n- 合同管理\n- 租金管理\n- 提醒管理\n- 报表统计\n- 基础信息查看')

# 报表统计标签页
class ReportTab(QWidget):
    # 导入全局auth_manager
    from user_auth import auth_manager
    def __init__(self):
        super().__init__()
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建报表类型选择区域
        report_type_layout = QHBoxLayout()
        
        report_type_label = QLabel('报表类型:')
        report_type_layout.addWidget(report_type_label)
        
        self.report_type_combo = QComboBox()
        self.report_type_combo.addItems(['合同统计报表', '租金收入报表', '到期提醒报表'])
        self.report_type_combo.currentIndexChanged.connect(self.onReportTypeChanged)
        report_type_layout.addWidget(self.report_type_combo)
        
        report_type_layout.addStretch()
        
        # 创建时间范围选择区域
        time_range_layout = QHBoxLayout()
        
        # 开始日期选择 - 确保标题与输入框水平向左对齐，间隔距离为2
        date_input_layout_1 = QHBoxLayout()
        start_date_label = QLabel('开始日期:')
        start_date_label.setAlignment(Qt.AlignLeft)
        date_input_layout_1.addWidget(start_date_label, alignment=Qt.AlignLeft)
        date_input_layout_1.setSpacing(2)  # 设置组件间隔为2
        
        self.start_date_edit = QDateEdit()
        self.start_date_edit.setCalendarPopup(True)
        self.start_date_edit.setDate(QDate.currentDate().addMonths(-12))
        date_input_layout_1.addWidget(self.start_date_edit, alignment=Qt.AlignLeft)
        time_range_layout.addLayout(date_input_layout_1)
        
        # 结束日期选择 - 确保标题与输入框水平向左对齐，间隔距离为2
        date_input_layout_2 = QHBoxLayout()
        end_date_label = QLabel('结束日期:')
        end_date_label.setAlignment(Qt.AlignLeft)
        date_input_layout_2.addWidget(end_date_label, alignment=Qt.AlignLeft)
        date_input_layout_2.setSpacing(2)  # 设置组件间隔为2
        
        self.end_date_edit = QDateEdit()
        self.end_date_edit.setCalendarPopup(True)
        self.end_date_edit.setDate(QDate.currentDate())
        date_input_layout_2.addWidget(self.end_date_edit, alignment=Qt.AlignLeft)
        time_range_layout.addLayout(date_input_layout_2)
        
        generate_button = QPushButton('生成报表')
        generate_button.clicked.connect(self.generateReport)
        time_range_layout.addWidget(generate_button)
        
        export_button = QPushButton('导出报表')
        export_button.clicked.connect(self.exportReport)
        time_range_layout.addWidget(export_button)
        
        # 创建图表和表格区域
        splitter = QSplitter(Qt.Vertical)
        
        # 创建图表区域
        chart_widget = QWidget()
        chart_layout = QVBoxLayout(chart_widget)
        
        self.chart_figure = Figure(figsize=(10, 4), dpi=100)
        self.chart_canvas = FigureCanvas(self.chart_figure)
        chart_layout.addWidget(self.chart_canvas)
        
        splitter.addWidget(chart_widget)
        
        # 创建数据表格
        self.report_table = QTableWidget()
        splitter.addWidget(self.report_table)
        
        # 设置分割器的初始大小
        splitter.setSizes([400, 400])
        
        # 添加所有区域到主布局
        main_layout.addLayout(report_type_layout)
        main_layout.addLayout(time_range_layout)
        main_layout.addWidget(splitter)
    
    def onReportTypeChanged(self, index):
        # 根据报表类型调整界面
        # 这里可以根据需要添加不同报表类型的特定控件
        pass
    
    def generateReport(self):
        # 生成报表
        report_type = self.report_type_combo.currentText()
        start_date = self.start_date_edit.date().toString('yyyy-MM-dd')
        end_date = self.end_date_edit.date().toString('yyyy-MM-dd')
        
        # 连接数据库 - 使用DatabaseUtils获取正确的连接
        conn = DatabaseUtils.get_connection()
        
        if report_type == '合同统计报表':
            self.generateContractReport(conn, start_date, end_date)
        elif report_type == '租金收入报表':
            self.generateRentReport(conn, start_date, end_date)
        elif report_type == '到期提醒报表':
            # 注意:方法名可能需要调整
            if hasattr(self, 'generateReminderReport'):
                self.generateReminderReport(conn, start_date, end_date)
            elif hasattr(self, 'generateExpiryReport'):
                self.generateExpiryReport(conn, start_date, end_date)
        # 注意:不再关闭连接,由DatabaseUtils管理连接池
    
    def generateContractReport(self, conn, start_date, end_date):
        # 生成合同统计报表
        # 查询合同数据
        cursor = conn.cursor()
        cursor.execute(
            "SELECT contract_no, sign_date, lessee, start_date, end_date, status, monthly_rent, annual_rent FROM contracts WHERE sign_date BETWEEN ? AND ?",
            (start_date, end_date)
        )
        contracts = cursor.fetchall()
        
        # 更新表格
        self.report_table.setRowCount(0)
        self.report_table.setColumnCount(8)
        self.report_table.setHorizontalHeaderLabels(['合同编号', '签约日期', '承租方', '租赁开始日期', '租赁截止日期', '合同状态', '月租金额', '年租金总额'])
        
        for row_idx, contract in enumerate(contracts):
            self.report_table.insertRow(row_idx)
            for col_idx, value in enumerate(contract):
                item = QTableWidgetItem(str(value) if value is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                self.report_table.setItem(row_idx, col_idx, item)
        
        # 调整列宽
        self.report_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        
        # 生成图表
        self.chart_figure.clear()
        
        # 统计不同状态的合同数量
        cursor.execute(
            "SELECT status, COUNT(*) FROM contracts WHERE sign_date BETWEEN ? AND ? GROUP BY status",
            (start_date, end_date)
        )
        status_data = cursor.fetchall()
        
        if status_data:
            # 获取当前主题颜色
            is_dark_theme = self._is_dark_theme()
            
            # 根据主题设置颜色
            if is_dark_theme:
                # 深色主题颜色 - 确保符合WCAG AA级对比度
                figure_bg = '#1a1a1a'       # 图表背景
                axes_bg = '#2d2d2d'         # 绘图区域背景
                text_color = '#ffffff'      # 主文本色（白色）
                title_color = '#ffffff'     # 标题颜色
                axis_color = '#d0d0d0'      # 坐标轴和标签颜色
                grid_color = '#404040'      # 网格线颜色
                bar_color = '#5DADE2'        # 柱状图颜色（亮蓝色）
                legend_bg = '#3a3a3a'        # 图例背景色
                legend_text = '#ffffff'      # 图例文本色
            else:
                # 明亮主题颜色
                figure_bg = '#ffffff'       # 图表背景
                axes_bg = '#ffffff'         # 绘图区域背景
                text_color = '#333333'      # 主文本色
                title_color = '#333333'     # 标题颜色
                axis_color = '#666666'      # 坐标轴和标签颜色
                grid_color = '#e0e0e0'      # 网格线颜色
                bar_color = '#2c3e50'        # 柱状图颜色（深灰色）
                legend_bg = '#ffffff'        # 图例背景色
                legend_text = '#333333'      # 图例文本色
            
            # 设置图表背景色
            self.chart_figure.patch.set_facecolor(figure_bg)
            
            statuses = [row[0] for row in status_data]
            counts = [row[1] for row in status_data]
            
            ax = self.chart_figure.add_subplot(111)
            
            # 设置轴背景色
            ax.set_facecolor(axes_bg)
            
            # 设置文本颜色
            for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
                         ax.get_xticklabels() + ax.get_yticklabels()):
                item.set_color(axis_color)
            
            # 添加网格线便于数值对比
            ax.grid(axis='y', linestyle='--', alpha=0.7, color=grid_color)
            
            # 绘制柱状图
            ax.bar(statuses, counts, color=bar_color, alpha=0.7)
            ax.set_xlabel('合同状态', fontsize=11, fontweight='bold', color=text_color)
            ax.set_ylabel('数量', fontsize=11, fontweight='bold', color=text_color)
            ax.set_title('合同状态分布', fontsize=13, fontweight='bold', color=title_color)
            
            self.chart_figure.tight_layout()
            self.chart_canvas.draw()
    
    def generateRentReport(self, conn, start_date, end_date):
        # 生成租金收入报表
        # 查询租金数据
        cursor = conn.cursor()
        cursor.execute(
            "SELECT contract_no, lessee, receipt_date, amount, period_start, period_end FROM rent_records WHERE receipt_date BETWEEN ? AND ?",
            (start_date, end_date)
        )
        rent_records = cursor.fetchall()
        
        # 更新表格
        self.report_table.setRowCount(0)
        self.report_table.setColumnCount(6)
        self.report_table.setHorizontalHeaderLabels(['合同编号', '承租方', '收款日期', '收款金额', '所属期间开始', '所属期间截止'])
        
        for row_idx, record in enumerate(rent_records):
            self.report_table.insertRow(row_idx)
            for col_idx, value in enumerate(record):
                item = QTableWidgetItem(str(value) if value is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                self.report_table.setItem(row_idx, col_idx, item)
        
        # 调整列宽
        self.report_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        
        # 生成图表
        self.chart_figure.clear()
        
        # 按月份统计租金收入
        cursor.execute(
            "SELECT strftime('%Y-%m', receipt_date) as month, SUM(amount) as total_amount FROM rent_records WHERE receipt_date BETWEEN ? AND ? GROUP BY month ORDER BY month",
            (start_date, end_date)
        )
        monthly_data = cursor.fetchall()
        
        if monthly_data:
            # 获取当前主题颜色
            is_dark_theme = self._is_dark_theme()
            
            # 根据主题设置颜色
            if is_dark_theme:
                # 深色主题颜色 - 确保符合WCAG AA级对比度
                figure_bg = '#1a1a1a'       # 图表背景
                axes_bg = '#2d2d2d'         # 绘图区域背景
                text_color = '#ffffff'      # 主文本色（白色）
                title_color = '#ffffff'     # 标题颜色
                axis_color = '#d0d0d0'      # 坐标轴和标签颜色
                grid_color = '#404040'      # 网格线颜色
                line_color = '#52BE80'       # 折线图颜色（亮绿色）
                marker_color = '#F5B7B1'     # 标记点颜色（亮红色）
                legend_bg = '#3a3a3a'        # 图例背景色
                legend_text = '#ffffff'      # 图例文本色
            else:
                # 明亮主题颜色
                figure_bg = '#ffffff'       # 图表背景
                axes_bg = '#ffffff'         # 绘图区域背景
                text_color = '#333333'      # 主文本色
                title_color = '#333333'     # 标题颜色
                axis_color = '#666666'      # 坐标轴和标签颜色
                grid_color = '#e0e0e0'      # 网格线颜色
                line_color = '#27ae60'       # 折线图颜色（绿色）
                marker_color = '#e74c3c'     # 标记点颜色（红色）
                legend_bg = '#ffffff'        # 图例背景色
                legend_text = '#333333'      # 图例文本色
            
            # 设置图表背景色
            self.chart_figure.patch.set_facecolor(figure_bg)
            
            months = [row[0] for row in monthly_data]
            amounts = [row[1] for row in monthly_data]
            
            ax = self.chart_figure.add_subplot(111)
            
            # 设置轴背景色
            ax.set_facecolor(axes_bg)
            
            # 设置文本颜色
            for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
                         ax.get_xticklabels() + ax.get_yticklabels()):
                item.set_color(axis_color)
            
            # 添加网格线便于数值对比
            ax.grid(axis='y', linestyle='--', alpha=0.7, color=grid_color)
            
            # 绘制折线图
            ax.plot(months, amounts, marker='o', color=line_color, markerfacecolor=marker_color, markersize=8)
            ax.set_xlabel('月份', fontsize=11, fontweight='bold', color=text_color)
            ax.set_ylabel('租金收入', fontsize=11, fontweight='bold', color=text_color)
            ax.set_title('月度租金收入趋势', fontsize=13, fontweight='bold', color=title_color)
            ax.tick_params(axis='x', rotation=45)
            
            self.chart_figure.tight_layout()
            self.chart_canvas.draw()
    
    def generateReminderReport(self, conn, start_date, end_date):
        # 生成到期提醒报表
        # 查询即将到期的合同
        cursor = conn.cursor()
        cursor.execute(
            "SELECT contract_no, lessee, end_date, monthly_rent FROM contracts WHERE status = '执行中' AND end_date BETWEEN ? AND ?",
            (start_date, end_date)
        )
        contracts = cursor.fetchall()
        
        # 更新表格
        self.report_table.setRowCount(0)
        self.report_table.setColumnCount(4)
        self.report_table.setHorizontalHeaderLabels(['合同编号', '承租方', '到期日期', '月租金额'])
        
        for row_idx, contract in enumerate(contracts):
            self.report_table.insertRow(row_idx)
            for col_idx, value in enumerate(contract):
                item = QTableWidgetItem(str(value) if value is not None else '')
                item.setTextAlignment(Qt.AlignCenter)
                self.report_table.setItem(row_idx, col_idx, item)
        
        # 调整列宽
        self.report_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        
        # 生成图表
        self.chart_figure.clear()
        
        if contracts:
            # 计算每个月到期的合同数量和租金金额
            today = date.today()
            contract_data = []
            
            for contract in contracts:
                end_date = datetime.strptime(contract[2], '%Y-%m-%d').date()
                month_key = f"{end_date.year}-{end_date.month:02d}"
                contract_data.append((month_key, contract[3]))
            
            # 按月统计
            month_stats = {}
            for month, rent in contract_data:
                if month not in month_stats:
                    month_stats[month] = {'count': 0, 'amount': 0}
                month_stats[month]['count'] += 1
                month_stats[month]['amount'] += rent
            
            # 排序
            sorted_months = sorted(month_stats.keys())
            counts = [month_stats[month]['count'] for month in sorted_months]
            amounts = [month_stats[month]['amount'] for month in sorted_months]
            
            # 获取当前主题颜色
            is_dark_theme = self._is_dark_theme()
            
            # 根据主题设置颜色
            if is_dark_theme:
                # 深色主题颜色 - 确保符合WCAG AA级对比度
                figure_bg = '#1a1a1a'       # 图表背景
                axes_bg = '#2d2d2d'         # 绘图区域背景
                text_color = '#ffffff'      # 主文本色（白色）
                title_color = '#ffffff'     # 标题颜色
                axis_color = '#d0d0d0'      # 坐标轴和标签颜色
                grid_color = '#404040'      # 网格线颜色
                bar_color = '#5DADE2'        # 柱状图颜色（亮蓝色）
                line_color = '#F5B7B1'       # 折线图颜色（亮红色）
                legend_bg = '#3a3a3a'        # 图例背景色
                legend_text = '#ffffff'      # 图例文本色
            else:
                # 明亮主题颜色
                figure_bg = '#ffffff'       # 图表背景
                axes_bg = '#ffffff'         # 绘图区域背景
                text_color = '#333333'      # 主文本色
                title_color = '#333333'     # 标题颜色
                axis_color = '#666666'      # 坐标轴和标签颜色
                grid_color = '#e0e0e0'      # 网格线颜色
                bar_color = 'b'              # 柱状图颜色（蓝色）
                line_color = 'r'             # 折线图颜色（红色）
                legend_bg = '#ffffff'        # 图例背景色
                legend_text = '#333333'      # 图例文本色
            
            # 设置图表背景色
            self.chart_figure.patch.set_facecolor(figure_bg)
            
            # 创建双Y轴图表
            ax1 = self.chart_figure.add_subplot(111)
            ax2 = ax1.twinx()
            
            # 设置轴背景色
            ax1.set_facecolor(axes_bg)
            
            # 设置文本颜色
            for item in ([ax1.title, ax1.xaxis.label, ax1.yaxis.label, ax2.yaxis.label] +
                         ax1.get_xticklabels() + ax1.get_yticklabels() + ax2.get_yticklabels()):
                item.set_color(axis_color)
            
            # 添加网格线便于数值对比
            ax1.grid(axis='y', linestyle='--', alpha=0.7, color=grid_color)
            
            # 绘制图表
            ax1.bar(sorted_months, counts, color=bar_color, alpha=0.6, label='到期合同数量')
            ax2.plot(sorted_months, amounts, color=line_color, marker='o', label='到期合同月租总额')
            
            # 设置坐标轴和标题
            ax1.set_xlabel('月份', fontsize=11, fontweight='bold', color=text_color)
            ax1.set_ylabel('到期合同数量', color=bar_color, fontsize=11, fontweight='bold')
            ax2.set_ylabel('到期合同月租总额', color=line_color, fontsize=11, fontweight='bold')
            ax1.set_title('即将到期合同统计', fontsize=13, fontweight='bold', color=title_color)
            
            # 设置图例
            lines1, labels1 = ax1.get_legend_handles_labels()
            lines2, labels2 = ax2.get_legend_handles_labels()
            legend = ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', fontsize=10, frameon=True, shadow=True)
            legend.get_frame().set_facecolor(legend_bg)
            for text in legend.get_texts():
                text.set_color(legend_text)
            
            self.chart_figure.tight_layout()
            self.chart_canvas.draw()
            
    def _is_dark_theme(self):
        """检测当前是否使用深色主题
        
        返回:
            bool: True表示深色主题，False表示明亮主题
        """
        try:
            # 尝试获取主题实例
            parent = self.parent()
            while parent:
                if hasattr(parent, 'theme'):
                    return parent.theme.name == 'dark'
                parent = parent.parent()
        except Exception:
            pass
        return False
    
    def exportReport(self):
        # 导出报表
        report_type = self.report_type_combo.currentText()
        
        # 如果表格为空,提示用户
        if self.report_table.rowCount() == 0:
            QMessageBox.warning(self, '警告', '当前没有可导出的数据,请先生成报表!')
            return
        
        # 创建导出数据对话框
        dialog = ExportDataDialog(self)
        if dialog.exec_():
            # 获取选择的导出格式
            export_format = dialog.getExportFormat()
            
            # 创建导出文件目录
            export_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '导出文件')
            if not os.path.exists(export_dir):
                os.makedirs(export_dir)
            
            # 生成文件名
            today = datetime.now().strftime("%Y%m%d_%H%M%S")
            
            try:
                if export_format == 'Excel':
                    # Excel格式导出
                    file_path = os.path.join(export_dir, f'{report_type}_{today}.xlsx')
                    self.exportToExcel(file_path)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'报表已成功导出到\n{file_path},并已自动打开文件')
                else:
                    # PDF格式导出
                    file_path = os.path.join(export_dir, f'{report_type}_{today}.pdf')
                    self.exportToPDF(file_path, report_type)
                    # 自动打开文件
                    os.startfile(file_path)
                    QMessageBox.information(self, '导出成功', f'报表已成功导出到\n{file_path},并已自动打开文件')
            except Exception as e:
                QMessageBox.critical(self, '导出失败', f'导出报表时发生错误:\n{str(e)}')
    
    def exportToExcel(self, file_path):
        # 导出数据到Excel并优化表格样式
        # 获取表格数据
        data = []
        headers = []
        
        # 获取表头
        for col_idx in range(self.report_table.columnCount()):
            headers.append(self.report_table.horizontalHeaderItem(col_idx).text())
        
        data.append(headers)
        
        # 获取表格内容
        for row_idx in range(self.report_table.rowCount()):
            row_data = []
            for col_idx in range(self.report_table.columnCount()):
                item = self.report_table.item(row_idx, col_idx)
                row_data.append(item.text() if item else '')
            data.append(row_data)
        
        # 创建DataFrame
        df = pd.DataFrame(data[1:], columns=data[0])
        
        # 创建ExcelWriter对象并应用样式
        from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
        from openpyxl.utils import get_column_letter
        
        with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
            # 将数据写入Excel
            df.to_excel(writer, index=False, sheet_name='报表数据')
            
            # 获取工作表
            worksheet = writer.sheets['报表数据']
            
            # 设置列宽自适应
            for col_idx, col in enumerate(worksheet.columns):
                max_length = 0
                column = col_idx + 1  # 列索引从1开始
                
                # 计算每列的最大宽度
                for cell in col:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                
                # 设置列宽（加一点边距）
                adjusted_width = (max_length + 2) * 1.2
                worksheet.column_dimensions[get_column_letter(column)].width = adjusted_width
            
            # 设置表头样式
            header_font = Font(bold=True, color="FFFFFF")
            header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
            border_style = Border(left=Side(style='thin'), 
                                 right=Side(style='thin'), 
                                 top=Side(style='thin'), 
                                 bottom=Side(style='thin'))
            
            # 应用表头样式
            for cell in worksheet[1]:
                cell.font = header_font
                cell.fill = header_fill
                cell.alignment = Alignment(horizontal="center", vertical="center")
                cell.border = border_style
            
            # 设置数据区域样式
            for row in worksheet.iter_rows(min_row=2, max_row=worksheet.max_row):
                for cell in row:
                    cell.alignment = Alignment(horizontal="center", vertical="center")
                    cell.border = border_style
    
    def exportToPDF(self, file_path, report_type):
        # 导出数据到PDF
        doc = SimpleDocTemplate(file_path, pagesize=letter)
        elements = []
        
        # 添加标题
        styles = getSampleStyleSheet()
        title = Paragraph(f"{report_type}", styles['Title'])
        elements.append(title)
        elements.append(Spacer(1, 12))
        
        # 添加报表生成日期
        today = datetime.now().strftime("%Y%m%d_%H%M%S")
        date_text = Paragraph(f"报表生成日期:{today}", styles['Normal'])
        elements.append(date_text)
        elements.append(Spacer(1, 12))
        
        # 准备表格数据
        data = []
        headers = []
        
        # 获取表头
        for col_idx in range(self.report_table.columnCount()):
            headers.append(self.report_table.horizontalHeaderItem(col_idx).text())
        
        data.append(headers)
        
        # 获取表格内容
        for row_idx in range(self.report_table.rowCount()):
            row_data = []
            for col_idx in range(self.report_table.columnCount()):
                item = self.report_table.item(row_idx, col_idx)
                row_data.append(item.text() if item else '')
            data.append(row_data)
        
        # 创建表格
        table = Table(data)
        
        # 设置表格样式
        table_style = TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            ('GRID', (0, 0), (-1, -1), 1, colors.black)
        ])
        table.setStyle(table_style)
        
        # 添加表格到元素列表
        elements.append(table)
        
        # 构建PDF
        doc.build(elements)

# 系统设置标签页
class SystemSettingTab(QWidget):
    def __init__(self):
        super().__init__()
        # 导入全局auth_manager和操作日志记录函数
        from user_auth import auth_manager
        from operation_logger import record_operation
        self.auth_manager = auth_manager
        self.record_operation = record_operation
        self.is_authenticated = False  # 初始状态为未认证
        self.initUI()  # 初始化UI,默认隐藏所有内容
        
    def initUI(self):
        # 确保导入了所有必要的组件
        from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QFileDialog, QMessageBox
        from PyQt5.QtCore import Qt
        
        # 创建主布局
        self.main_layout = QVBoxLayout(self)
        
        # 创建认证提示标签
        self.auth_prompt = QLabel('请先输入系统设置访问密码以解锁功能')
        self.auth_prompt.setAlignment(Qt.AlignCenter)
        self.auth_prompt.setStyleSheet('font-size: 16px; color: #666; padding: 40px;')
        self.main_layout.addWidget(self.auth_prompt)
        
        # 创建主框架（默认隐藏）
        self.main_frame = QFrame()
        self.main_frame.setFrameShape(QFrame.StyledPanel)
        self.main_frame.hide()  # 默认隐藏所有系统设置内容
        self.main_layout.addWidget(self.main_frame)
        
        # 创建主框架布局
        frame_layout = QVBoxLayout(self.main_frame)
        
        # 创建标题标签
        title_label = QLabel('系统设置')
        title_label.setStyleSheet('font-size: 18px; font-weight: bold; margin-bottom: 10px;')
        frame_layout.addWidget(title_label)
        
        # 创建两个子框架的水平布局
        sub_frames_layout = QHBoxLayout()
        sub_frames_layout.setSpacing(20)  # 设置框架间距
        frame_layout.addLayout(sub_frames_layout)
        
        # 创建数据维护和自动备份设置的容器框架
        self.data_maintenance_container = QFrame()
        self.data_maintenance_container.setFrameShape(QFrame.StyledPanel)
        self.data_maintenance_container.setMinimumWidth(300)
        self.data_maintenance_container.setMaximumWidth(350)
        sub_frames_layout.addWidget(self.data_maintenance_container)
        
        # 创建容器的垂直布局
        data_maintenance_container_layout = QVBoxLayout(self.data_maintenance_container)
        
        # 创建数据维护框架 - 添加边框线
        self.data_maintenance_frame = QFrame()
        self.data_maintenance_frame.setFrameShape(QFrame.StyledPanel)
        self.data_maintenance_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        data_maintenance_container_layout.addWidget(self.data_maintenance_frame)
        
        # 数据维护框架布局
        data_layout = QVBoxLayout(self.data_maintenance_frame)
        
        # 数据维护标题 - 添加主题色背景
        data_title = QLabel('数据维护')
        data_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        data_layout.addWidget(data_title)
        
        # 创建数据库按钮
        self.create_db_btn = QPushButton('创建数据库')
        self.create_db_btn.setMinimumHeight(40)
        self.create_db_btn.clicked.connect(self.createDatabase)
        data_layout.addWidget(self.create_db_btn)
        
        # 选择数据库按钮
        self.select_db_btn = QPushButton('选择数据库')
        self.select_db_btn.setMinimumHeight(40)
        self.select_db_btn.clicked.connect(self.selectDatabase)
        data_layout.addWidget(self.select_db_btn)
        
        # 备份数据按钮
        self.backup_btn = QPushButton('备份数据')
        self.backup_btn.setMinimumHeight(40)
        self.backup_btn.clicked.connect(self.backupData)
        data_layout.addWidget(self.backup_btn)
        
        # 数据恢复按钮
        self.restore_btn = QPushButton('数据恢复')
        self.restore_btn.setMinimumHeight(40)
        self.restore_btn.clicked.connect(self.restoreData)
        data_layout.addWidget(self.restore_btn)
        
        # 数据初始化按钮
        self.init_btn = QPushButton('数据初始化')
        self.init_btn.setMinimumHeight(40)
        self.init_btn.clicked.connect(self.initData)
        data_layout.addWidget(self.init_btn)
        
        # 数据库优化按钮
        self.optimize_db_btn = QPushButton('数据库优化')
        self.optimize_db_btn.setMinimumHeight(40)
        self.optimize_db_btn.clicked.connect(self.optimizeDatabase)
        data_layout.addWidget(self.optimize_db_btn)
        
        # 查看日志按钮
        self.view_log_btn = QPushButton('查看日志')
        self.view_log_btn.setMinimumHeight(40)
        self.view_log_btn.clicked.connect(self.viewLogs)
        data_layout.addWidget(self.view_log_btn)
        
        # 添加垂直伸缩空间
        data_layout.addStretch(1)
        
        # 添加分割线（数据维护和自动备份设置之间）
        divider_data_backup = QFrame()
        divider_data_backup.setFrameShape(QFrame.HLine)
        divider_data_backup.setFrameShadow(QFrame.Sunken)
        divider_data_backup.setStyleSheet('margin: 10px 0;')
        data_maintenance_container_layout.addWidget(divider_data_backup)
        
        # 创建自动备份设置框架 - 添加边框线
        self.auto_backup_frame = QFrame()
        self.auto_backup_frame.setFrameShape(QFrame.StyledPanel)
        self.auto_backup_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        data_maintenance_container_layout.addWidget(self.auto_backup_frame)
        
        # 创建配置和提醒设置的容器框架
        self.config_reminder_container = QFrame()
        self.config_reminder_container.setFrameShape(QFrame.StyledPanel)
        self.config_reminder_container.setMinimumWidth(300)
        self.config_reminder_container.setMaximumWidth(350)
        sub_frames_layout.addWidget(self.config_reminder_container)
        
        # 创建容器的垂直布局
        container_layout = QVBoxLayout(self.config_reminder_container)
        
        # 创建配置文件设置框架 - 添加边框线
        self.config_settings_frame = QFrame()
        self.config_settings_frame.setFrameShape(QFrame.StyledPanel)
        self.config_settings_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        container_layout.addWidget(self.config_settings_frame)
        
        # 配置文件设置框架布局
        config_layout = QVBoxLayout(self.config_settings_frame)
        
        # 配置文件设置标题 - 添加主题色背景
        config_title = QLabel('配置文件设置')
        config_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        config_layout.addWidget(config_title)
        
        # 当前配置文件路径显示
        current_config_layout = QHBoxLayout()
        current_config_label = QLabel('当前路径:')
        current_config_label.setMinimumWidth(80)
        self.current_config_path = QLineEdit()
        self.current_config_path.setMinimumHeight(30)
        self.current_config_path.setReadOnly(True)
        self.current_config_path.setStyleSheet('background-color: #f0f0f0; font-size: 10px;')
        current_config_layout.addWidget(current_config_label)
        current_config_layout.addWidget(self.current_config_path)
        config_layout.addLayout(current_config_layout)
        
        # 设置配置文件路径按钮
        self.set_config_btn = QPushButton('设置自定义路径')
        self.set_config_btn.setMinimumHeight(40)
        self.set_config_btn.clicked.connect(self.setCustomConfigPath)
        config_layout.addWidget(self.set_config_btn)
        
        # 重置为默认路径按钮
        self.reset_config_btn = QPushButton('重置为默认路径')
        self.reset_config_btn.setMinimumHeight(40)
        self.reset_config_btn.clicked.connect(self.resetConfigPath)
        config_layout.addWidget(self.reset_config_btn)
        
        # 添加配置说明
        config_note = QLabel('注意：修改配置文件路径后，系统将使用新路径的配置文件')
        config_note.setStyleSheet('color: #666; font-size: 10px; margin-top: 10px;')
        config_layout.addWidget(config_note)
        
        # 添加垂直伸缩空间
        config_layout.addStretch(1)
        
        # 添加分割线
        divider = QFrame()
        divider.setFrameShape(QFrame.HLine)
        divider.setFrameShadow(QFrame.Sunken)
        divider.setStyleSheet('margin: 10px 0;')
        container_layout.addWidget(divider)
        
        # 创建提醒设置框架 - 添加边框线
        self.reminder_settings_frame = QFrame()
        self.reminder_settings_frame.setFrameShape(QFrame.StyledPanel)
        self.reminder_settings_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        container_layout.addWidget(self.reminder_settings_frame)
        
        # 添加分割线（配置和提醒设置与软件信息之间）
        divider2 = QFrame()
        divider2.setFrameShape(QFrame.HLine)
        divider2.setFrameShadow(QFrame.Sunken)
        divider2.setStyleSheet('margin: 10px 0;')
        container_layout.addWidget(divider2)
        
        # 创建软件信息框架 - 添加边框线
        self.software_info_frame = QFrame()
        self.software_info_frame.setFrameShape(QFrame.StyledPanel)
        self.software_info_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        container_layout.addWidget(self.software_info_frame)
        
        # 软件信息框架布局
        software_layout = QVBoxLayout(self.software_info_frame)
        
        # 软件信息标题 - 添加主题色背景
        software_title = QLabel('软件信息')
        software_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        software_layout.addWidget(software_title)
        
        # 软件品牌输入框
        brand_layout = QHBoxLayout()
        brand_label = QLabel('软件品牌:')
        brand_label.setMinimumWidth(80)
        self.brand_input = QLineEdit()
        self.brand_input.setMinimumHeight(30)
        brand_layout.addWidget(brand_label)
        brand_layout.addWidget(self.brand_input)
        software_layout.addLayout(brand_layout)
        
        # 软件名称输入框
        name_layout = QHBoxLayout()
        name_label = QLabel('软件名称:')
        name_label.setMinimumWidth(80)
        self.name_input = QLineEdit()
        self.name_input.setMinimumHeight(30)
        name_layout.addWidget(name_label)
        name_layout.addWidget(self.name_input)
        software_layout.addLayout(name_layout)
        
        # 软件版本输入框
        version_layout = QHBoxLayout()
        version_label = QLabel('软件版本:')
        version_label.setMinimumWidth(80)
        self.version_input = QLineEdit()
        self.version_input.setMinimumHeight(30)
        version_layout.addWidget(version_label)
        version_layout.addWidget(self.version_input)
        software_layout.addLayout(version_layout)
        
        # 开发时间输入框
        dev_time_layout = QHBoxLayout()
        dev_time_label = QLabel('开发时间:')
        dev_time_label.setMinimumWidth(80)
        self.dev_time_input = QLineEdit()
        self.dev_time_input.setMinimumHeight(30)
        dev_time_layout.addWidget(dev_time_label)
        dev_time_layout.addWidget(self.dev_time_input)
        software_layout.addLayout(dev_time_layout)
        
        # 保存软件信息按钮
        self.save_software_btn = QPushButton('保存软件信息')
        self.save_software_btn.setMinimumHeight(40)
        self.save_software_btn.clicked.connect(self.saveSoftwareInfo)
        software_layout.addWidget(self.save_software_btn)
        
        # 在软件信息框架布局末尾添加垂直伸缩空间
        software_layout.addStretch(1)
        
        # 在容器布局末尾添加垂直伸缩空间
        container_layout.addStretch(1)
        
        # 在数据维护容器布局末尾添加垂直伸缩空间
        data_maintenance_container_layout.addStretch(1)
        
        # 自动备份设置框架布局
        auto_backup_layout = QVBoxLayout(self.auto_backup_frame)
        
        # 移除自动备份设置标题标签，保持布局简洁
        
        # 提醒设置框架布局
        reminder_layout = QVBoxLayout(self.reminder_settings_frame)
        
        # 提醒设置标题 - 添加主题色背景
        reminder_title = QLabel('提醒设置')
        reminder_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        reminder_layout.addWidget(reminder_title)
        
        # 合同提前提醒天数输入框
        contract_reminder_layout = QHBoxLayout()
        contract_reminder_label = QLabel('合同提前提醒天数:')
        contract_reminder_label.setMinimumWidth(120)
        self.contract_reminder_input = QLineEdit()
        self.contract_reminder_input.setMinimumHeight(30)
        # 设置整数验证器
        from PyQt5.QtGui import QIntValidator
        self.contract_reminder_input.setValidator(QIntValidator(0, 999))
        contract_reminder_layout.addWidget(contract_reminder_label)
        contract_reminder_layout.addWidget(self.contract_reminder_input)
        reminder_layout.addLayout(contract_reminder_layout)
        
        # 租金提前提醒天数输入框
        rent_reminder_layout = QHBoxLayout()
        rent_reminder_label = QLabel('租金提前提醒天数:')
        rent_reminder_label.setMinimumWidth(120)
        self.rent_reminder_input = QLineEdit()
        self.rent_reminder_input.setMinimumHeight(30)
        self.rent_reminder_input.setValidator(QIntValidator(0, 999))
        rent_reminder_layout.addWidget(rent_reminder_label)
        rent_reminder_layout.addWidget(self.rent_reminder_input)
        reminder_layout.addLayout(rent_reminder_layout)
        
        # 屏幕超时设置
        timeout_layout = QHBoxLayout()
        timeout_label = QLabel('屏幕超时时间(分钟):')
        timeout_label.setMinimumWidth(120)
        self.timeout_input = QLineEdit()
        self.timeout_input.setMinimumHeight(30)
        self.timeout_input.setValidator(QIntValidator(1, 999))
        timeout_layout.addWidget(timeout_label)
        timeout_layout.addWidget(self.timeout_input)
        reminder_layout.addLayout(timeout_layout)
        
        # 保存提醒设置按钮
        self.save_reminder_btn = QPushButton('保存提醒设置')
        self.save_reminder_btn.setMinimumHeight(40)
        self.save_reminder_btn.clicked.connect(self.saveReminderSettings)
        reminder_layout.addWidget(self.save_reminder_btn)
        
        # 添加垂直伸缩空间
        reminder_layout.addStretch(1)
        

        # 自动备份设置标题 - 添加主题色背景
        auto_backup_title = QLabel('自动备份设置')
        auto_backup_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        auto_backup_layout.addWidget(auto_backup_title)
        
        # 启用自动备份开关
        auto_backup_enable_layout = QHBoxLayout()
        auto_backup_enable_label = QLabel('启用自动备份:')
        auto_backup_enable_label.setMinimumWidth(120)
        from PyQt5.QtWidgets import QCheckBox
        self.auto_backup_enable = QCheckBox()
        auto_backup_enable_layout.addWidget(auto_backup_enable_label)
        auto_backup_enable_layout.addWidget(self.auto_backup_enable)
        auto_backup_layout.addLayout(auto_backup_enable_layout)
        
        # 备份频率选择
        frequency_layout = QHBoxLayout()
        frequency_label = QLabel('备份频率:')
        frequency_label.setMinimumWidth(120)
        from PyQt5.QtWidgets import QComboBox
        self.frequency_combo = QComboBox()
        self.frequency_combo.addItems(['每天', '每周', '每月'])
        self.frequency_combo.setMinimumHeight(30)
        frequency_layout.addWidget(frequency_label)
        frequency_layout.addWidget(self.frequency_combo)
        auto_backup_layout.addLayout(frequency_layout)
        
        # 备份时间选择
        time_layout = QHBoxLayout()
        time_label = QLabel('备份时间:')
        time_label.setMinimumWidth(120)
        from PyQt5.QtWidgets import QTimeEdit
        self.backup_time_edit = QTimeEdit()
        self.backup_time_edit.setDisplayFormat('HH:mm')
        self.backup_time_edit.setMinimumHeight(30)
        time_layout.addWidget(time_label)
        time_layout.addWidget(self.backup_time_edit)
        auto_backup_layout.addLayout(time_layout)
        
        # 备份路径设置
        path_layout = QHBoxLayout()
        path_label = QLabel('备份路径:')
        path_label.setMinimumWidth(120)
        self.backup_path_input = QLineEdit()
        self.backup_path_input.setMinimumHeight(30)
        self.backup_path_input.setReadOnly(True)
        self.backup_path_button = QPushButton('浏览...')
        self.backup_path_button.setMinimumHeight(30)
        self.backup_path_button.clicked.connect(self.selectBackupPath)
        path_layout.addWidget(path_label)
        path_layout.addWidget(self.backup_path_input)
        path_layout.addWidget(self.backup_path_button)
        auto_backup_layout.addLayout(path_layout)
        
        # 保存自动备份设置按钮
        self.save_auto_backup_btn = QPushButton('保存自动备份设置')
        self.save_auto_backup_btn.setMinimumHeight(40)
        self.save_auto_backup_btn.clicked.connect(self.saveAutoBackupSettings)
        auto_backup_layout.addWidget(self.save_auto_backup_btn)
        
        # 自动备份状态显示
        self.backup_status_label = QLabel('自动备份状态: 未配置')
        self.backup_status_label.setStyleSheet('color: #666; font-size: 12px; margin-top: 10px;')
        auto_backup_layout.addWidget(self.backup_status_label)
        
        # 在自动备份设置框架布局末尾添加垂直伸缩空间
        auto_backup_layout.addStretch(1)
        

        # 填充空间
        data_layout.addStretch(1)
        

        # 用户管理框架 - 添加边框线
        self.user_management_frame = QFrame()
        self.user_management_frame.setFrameShape(QFrame.StyledPanel)
        self.user_management_frame.setStyleSheet('border: 1px solid #CCCCCC; border-radius: 4px; padding: 0; margin: 0;')
        sub_frames_layout.addWidget(self.user_management_frame)
        
        # 用户管理框架布局
        user_layout = QVBoxLayout(self.user_management_frame)
        
        # 用户管理标题 - 添加主题色背景
        user_title = QLabel('用户管理')
        user_title.setStyleSheet('font-size: 16px; font-weight: bold; background-color: #1976D2; color: white; padding: 8px 12px; margin: 0;')
        user_layout.addWidget(user_title)
        
        # 用户信息输入区域
        input_frame = QFrame()
        input_frame.setFrameShape(QFrame.StyledPanel)
        user_layout.addWidget(input_frame)
        
        input_layout = QGridLayout(input_frame)
        
        # 用户名
        input_layout.addWidget(QLabel('用户名:'), 0, 0)
        self.username_edit = QLineEdit()
        input_layout.addWidget(self.username_edit, 0, 1)
        
        # 密码
        input_layout.addWidget(QLabel('密码:'), 1, 0)
        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        input_layout.addWidget(self.password_edit, 1, 1)
        
        # 角色
        input_layout.addWidget(QLabel('角色:'), 2, 0)
        self.role_combo = QComboBox()
        self.role_combo.addItems(['管理员', '操作员'])
        input_layout.addWidget(self.role_combo, 2, 1)
        
        # 按钮区域
        btn_layout = QHBoxLayout()
        user_layout.addLayout(btn_layout)
        
        # 添加用户按钮
        self.add_user_btn = QPushButton('添加用户')
        self.add_user_btn.clicked.connect(self.addUser)
        btn_layout.addWidget(self.add_user_btn)
        
        # 更新用户按钮
        self.update_user_btn = QPushButton('更新用户')
        self.update_user_btn.clicked.connect(self.updateUser)
        btn_layout.addWidget(self.update_user_btn)
        
        # 删除用户按钮
        self.delete_user_btn = QPushButton('删除用户')
        self.delete_user_btn.clicked.connect(self.deleteUser)
        btn_layout.addWidget(self.delete_user_btn)
        
        # 用户列表
        self.user_table = QTableWidget()
        self.user_table.setColumnCount(3)
        self.user_table.setHorizontalHeaderLabels(['用户名', '密码', '角色'])
        self.user_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.user_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.user_table.cellClicked.connect(self.onUserTableClicked)
        user_layout.addWidget(self.user_table)
        
    def loadUserData(self):
        """加载用户数据到表格"""
        from db_utils import DatabaseUtils
        try:
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            cursor.execute("SELECT username, password, role FROM users")
            users = cursor.fetchall()
            
            self.user_table.setRowCount(0)
            for row_idx, user in enumerate(users):
                self.user_table.insertRow(row_idx)
                for col_idx, data in enumerate(user):
                    # 密码列显示为星号
                    if col_idx == 1:
                        item = QTableWidgetItem('****')
                    else:
                        item = QTableWidgetItem(str(data))
                    self.user_table.setItem(row_idx, col_idx, item)
            
            conn.close()
        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载用户数据失败: {str(e)}')
            
    def onUserTableClicked(self, row, col):
        """当用户点击表格时,填充输入框"""
        username = self.user_table.item(row, 0).text()
        role = self.user_table.item(row, 2).text()
        
        self.username_edit.setText(username)
        self.password_edit.clear()
        self.role_combo.setCurrentText(role)
        
    def addUser(self):
        """添加用户"""
        username = self.username_edit.text().strip()
        password = self.password_edit.text().strip()
        role = self.role_combo.currentText()
        
        if not username or not password:
            QMessageBox.warning(self, '警告', '用户名和密码不能为空')
            return
        
        try:
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 检查用户是否已存在
            cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
            if cursor.fetchone():
                QMessageBox.warning(self, '警告', '用户名已存在')
                DatabaseUtils.close_connection(conn)
                # 记录操作失败日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="用户管理",
                    operation_content=f"尝试添加用户 '{username}'",
                    operation_result="失败",
                    detail={"用户名": username, "原因": "用户名已存在"}
                )
                return
            
            # 添加新用户
            cursor.execute("INSERT INTO users (username, password, role) VALUES (?, ?, ?)", (username, password, role))
            conn.commit()
            DatabaseUtils.close_connection(conn)
            
            QMessageBox.information(self, '成功', '用户添加成功')
            self.loadUserData()
            self.clearInputs()
            
            # 记录操作成功日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="用户管理",
                operation_content=f"添加用户 '{username}'",
                operation_result="成功",
                detail=f"角色: {role}"
            )
        except Exception as e:
            QMessageBox.critical(self, '错误', f'添加用户失败: {str(e)}')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="用户管理",
                operation_content=f"尝试添加用户 '{username}'",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
            
    def updateUser(self):
        """更新用户"""
        username = self.username_edit.text().strip()
        password = self.password_edit.text().strip()
        role = self.role_combo.currentText()
        
        if not username:
            QMessageBox.warning(self, '警告', '请选择要更新的用户')
            return
        
        try:
            # 使用DatabaseUtils获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 检查用户是否存在
            cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
            if not cursor.fetchone():
                QMessageBox.warning(self, '警告', '用户不存在')
                conn.close()
                # 记录操作失败日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="用户管理",
                    operation_content=f"尝试更新用户 '{username}'",
                    operation_result="失败",
                    detail={"用户名": username, "原因": "用户不存在"}
                )
                return
            
            # 更新用户信息
            if password:
                cursor.execute("UPDATE users SET password = ?, role = ? WHERE username = ?", (password, role, username))
                details = f"更新密码和角色为 '{role}'"
            else:
                cursor.execute("UPDATE users SET role = ? WHERE username = ?", (role, username))
                details = f"更新角色为 '{role}'"
                
            conn.commit()
            conn.close()
            
            QMessageBox.information(self, '成功', '用户更新成功')
            self.loadUserData()
            
            # 记录操作成功日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="用户管理",
                operation_content=f"更新用户 '{username}'",
                operation_result="成功",
                detail={"详情": details}
            )
        except Exception as e:
            QMessageBox.critical(self, '错误', f'更新用户失败: {str(e)}')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="用户管理",
                operation_content=f"尝试更新用户 '{username}'",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
    
    def viewLogs(self):
        """查看系统操作日志"""
        try:
            import importlib
            import sys
            import os
            
            # 获取当前脚本所在目录
            script_dir = os.path.dirname(os.path.abspath(__file__))
            # 将当前目录添加到Python路径
            if script_dir not in sys.path:
                sys.path.append(script_dir)
                
            # 动态导入log_viewer模块
            log_viewer_module = importlib.import_module('log_viewer')
            
            # 创建并显示日志查看器
            log_viewer = log_viewer_module.LogViewer()
            # 保存日志查看器引用到类属性,防止被垃圾回收
            self.log_viewer = log_viewer
            log_viewer.show()
            
            # 记录操作成功日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="查看系统日志",
                operation_result="成功",
                detail={"操作": "打开日志查看器"}
            )
        except Exception as e:
            QMessageBox.critical(self, '错误', f'打开日志查看器失败: {str(e)}')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="尝试查看系统日志",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
    
    def selectDatabase(self):
        """选择数据库文件并切换数据库"""
        from db_utils import DatabaseUtils
        from config_utils import ConfigManager
        from PyQt5.QtWidgets import QFileDialog, QMessageBox
        from PyQt5.QtWidgets import QApplication
        import os
        import sqlite3
        from logger_module import log_info, log_error
        
        try:
            # 打开文件选择对话框
            file_path, _ = QFileDialog.getOpenFileName(
                self, 
                '选择数据库文件', 
                '', 
                'SQLite数据库文件 (*.db);;所有文件 (*.*)'
            )
            
            if file_path:
                # 路径验证
                if not os.path.exists(file_path):
                    QMessageBox.critical(self, '错误', '数据库文件不存在')
                    return
                
                if not os.access(file_path, os.R_OK | os.W_OK):
                    QMessageBox.critical(self, '错误', '数据库文件没有读写权限')
                    return
                
                # 验证选择的文件是否为有效的SQLite数据库
                try:
                    # 测试数据库连接
                    conn = sqlite3.connect(file_path)
                    cursor = conn.cursor()
                    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
                    tables = cursor.fetchall()
                    conn.close()
                    
                    # 检查是否包含必要的表
                    required_tables = ['contracts', 'users', 'reminder_settings']
                    found_tables = [table[0] for table in tables]
                    
                    missing_tables = [table for table in required_tables if table not in found_tables]
                    
                    if missing_tables:
                        reply = QMessageBox.question(
                            self,
                            '警告',
                            '所选数据库文件缺少以下必要表: ' + ', '.join(missing_tables) + '\n继续使用此数据库可能导致程序功能异常,是否继续?',
                            QMessageBox.Yes | QMessageBox.No,
                            QMessageBox.No
                        ) 
                        if reply != QMessageBox.Yes:
                            return
                    
                    # 使用ConfigManager设置新的数据库路径
                    success = ConfigManager.set_database_path(file_path)
                    
                    if success:
                        log_info(f"数据库路径设置成功: {file_path}")
                        
                        # 更新DatabaseUtils中的数据库路径
                        DatabaseUtils.set_db_path(file_path)
                        
                        # 记录操作日志
                        self.record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="系统设置",
                            operation_content="选择数据库",
                            operation_result="成功",
                            detail={"数据库路径": file_path}
                        )
                        
                        # 尝试更新主窗口的数据库名称标签
                        for widget in QApplication.topLevelWidgets():
                            if hasattr(widget, 'update_db_name_label'):
                                widget.update_db_name_label()
                                log_info("主窗口数据库名称标签已更新")
                                break
                        
                        # 提示用户重启程序以应用更改
                        QMessageBox.information(
                            self,
                            '成功',
                            '数据库选择成功!\n\n' 
                            '数据库路径已更新,状态栏显示的数据库名称也已更新。\n' 
                            '为了确保所有功能正常运行,请重启程序以完全应用新的数据库配置。'
                            
                        )
                    else:
                        log_error(f"数据库路径设置失败: {file_path}")
                        QMessageBox.critical(self, '错误', '保存数据库路径失败,请检查文件权限')
                        
                except Exception as e:
                    log_error(f"数据库验证失败: {str(e)}")
                    QMessageBox.critical(
                        self,
                        '错误',
                        f'选择的文件不是有效的SQLite数据库: {str(e)}'
                    )
                    return
        
        except Exception as e:
            log_error(f"选择数据库过程异常: {str(e)}")
            QMessageBox.critical(
                self,
                '错误',
                f'选择数据库失败: {str(e)}'
            )
            # 记录错误日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="选择数据库",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
    
    def createDatabase(self):
        """
        创建新的数据库文件
        使用database_creator模块中的DatabaseCreator类来实现数据库创建功能
        """
        from logger_module import log_info, log_error
        
        try:
            log_info("用户尝试创建新数据库")
            
            # 调用DatabaseCreator创建新数据库
            success, message = DatabaseCreator.create_new_database(self)
            
            # 记录操作日志
            if success:
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="系统设置",
                    operation_content="创建数据库",
                    operation_result="成功",
                    detail={"消息": message}
                )
            else:
                # 如果不是用户取消操作，则记录为失败
                if "取消" not in message:
                    self.record_operation(
                        user_id=self.auth_manager.current_user_id,
                        username=self.auth_manager.current_user,
                        operation_module="系统设置",
                        operation_content="创建数据库",
                        operation_result="失败",
                        detail={"消息": message}
                    )
                    log_warning(f"数据库创建失败: {message}")
                else:
                    log_info("用户取消了数据库创建")
                    
        except Exception as e:
            error_msg = f"创建数据库过程异常: {str(e)}"
            log_error(error_msg)
            
            # 记录错误操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="创建数据库",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
            
            # 显示错误消息
            from PyQt5.QtWidgets import QMessageBox
            QMessageBox.critical(
                self,
                '错误',
                f'创建数据库失败: {str(e)}'
            )
            
    def deleteUser(self):
        """删除用户"""
        username = self.username_edit.text().strip()
        
        if not username:
            QMessageBox.warning(self, '警告', '请选择要删除的用户')
            return
        
        # 不允许删除admin用户
        if username == 'admin':
            QMessageBox.warning(self, '警告', '不允许删除管理员用户')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="用户管理",
                operation_content=f"尝试删除用户 '{username}'",
                operation_result="失败",
                detail={"原因": "不允许删除管理员用户"}
            )
            return
        
        # 确认删除
        reply = QMessageBox.question(self, '确认', f'确定要删除用户 {username} 吗?', 
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            try:
                # 使用DatabaseUtils执行数据库操作
                conn = DatabaseUtils.get_connection()
                cursor = conn.cursor()
                cursor.execute("DELETE FROM users WHERE username = ?", (username,))
                conn.commit()
                DatabaseUtils.close_connection(conn)
                
                QMessageBox.information(self, '成功', '用户删除成功')
                self.loadUserData()
                self.clearInputs()
                
                # 记录操作成功日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="用户管理",
                    operation_content=f"删除用户 '{username}'",
                    operation_result="成功",
                    detail={}
                )
            except Exception as e:
                QMessageBox.critical(self, '错误', f'删除用户失败: {str(e)}')
                # 记录操作失败日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="用户管理",
                    operation_content=f"尝试删除用户 '{username}'",
                    operation_result="失败",
                    detail={"错误信息": str(e)}
                )
                
    def clearInputs(self):
        """清空输入框"""
        self.username_edit.clear()
        self.password_edit.clear()
        self.role_combo.setCurrentIndex(0)
        
    def backupData(self):
        """备份数据"""
        try:
            # 导入DatabaseUtils
            from db_utils import DatabaseUtils
            
            # 选择备份文件保存路径
            # 获取当前数据库文件名称
            current_db_path = DatabaseUtils.get_db_path()
            current_db_name = os.path.basename(current_db_path)
            db_name_without_ext = os.path.splitext(current_db_name)[0]
            
            # 构建新的备份文件名格式：当前数据库文件名_backup_时间戳.db
            backup_filename = f'{db_name_without_ext}_backup_{datetime.now().strftime("%Y%m%d_%H%M%S")}.db'
            
            backup_path, _ = QFileDialog.getSaveFileName(
                self, '备份数据库', 
                os.path.join(os.path.expanduser('~'), backup_filename),
                'SQLite 数据库 (*.db);;所有文件 (*)' 
            )
            
            if not backup_path:
                return
            
            # 获取当前数据库路径
            db_path = DatabaseUtils.get_db_path()
            
            # 复制数据库文件
            import shutil
            shutil.copy2(db_path, backup_path)
            
            QMessageBox.information(self, '成功', f'数据备份成功\n备份文件: {backup_path}')
        except Exception as e:
            QMessageBox.critical(self, '错误', f'数据备份失败: {str(e)}')
            
    def restoreData(self):
        """恢复数据"""
        try:
            # 导入DatabaseUtils
            from db_utils import DatabaseUtils
            
            # 选择备份文件
            backup_path, _ = QFileDialog.getOpenFileName(
                self, '恢复数据库', '', 'SQLite 数据库 (*.db);;所有文件 (*)' 
            )
            
            if not backup_path:
                return
            
            # 确认恢复
            reply = QMessageBox.question(self, '确认', '恢复数据将覆盖当前所有数据,是否继续?', 
                                        QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                # 获取当前数据库路径
                db_path = DatabaseUtils.get_db_path()
                
                # 复制备份文件到当前数据库
                import shutil
                shutil.copy2(backup_path, db_path)
                
                QMessageBox.information(self, '成功', '数据恢复成功,请重启应用程序以加载新数据')
        except Exception as e:
            QMessageBox.critical(self, '错误', f'数据恢复失败: {str(e)}')
            
    def initData(self):
        """数据初始化功能 - 动态加载数据库表版本"""
        # 导入必要的模块
        from db_utils import DatabaseUtils
        import sqlite3
        
        # 创建数据表选择对话框
        class DataInitDialog(QDialog):
            def __init__(self, parent=None):
                super().__init__(parent)
                self.setWindowTitle('数据初始化')
                self.setMinimumSize(800, 600)
                
                # 表名中文映射字典
                self.table_name_mapping = {
                    'contracts': '合同表',
                    'rent_records': '租金记录表',
                    'reminder_settings': '提醒设置表',
                    'users': '用户表',
                    'houses': '房屋资料',
                    'landlords': '出租人资料',
                    'tenants': '承租人资料',
                    'notes': '笔记表',
                    'system_params': '系统参数表',
                    'operation_logs': '操作日志表',
                    'utility_fee': '水电费记录表'
                }
                
                # 创建表格视图
                self.table_widget = QTableWidget(0, 5)
                self.table_widget.setHorizontalHeaderLabels(['选择', '表名(中文)', '表名(英文)', '记录数', '创建时间'])
                
                # 设置列宽
                self.table_widget.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
                self.table_widget.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
                self.table_widget.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents)
                self.table_widget.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeToContents)
                self.table_widget.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeToContents)
                
                # 设置行高，确保选择框完全可见
                self.table_widget.verticalHeader().setDefaultSectionSize(50)
                # 设置最小行高，防止行高被压缩
                self.table_widget.verticalHeader().setMinimumSectionSize(40)
                
                # 添加状态栏显示表数量
                self.status_label = QLabel("正在加载数据库表信息...")
                
                # 创建按钮
                refresh_button = QPushButton('刷新表信息')
                select_all_button = QPushButton('全选')
                deselect_all_button = QPushButton('取消全选')
                confirm_button = QPushButton('确认初始化')
                cancel_button = QPushButton('取消')
                
                # 连接信号
                refresh_button.clicked.connect(self.load_database_tables)
                select_all_button.clicked.connect(self.select_all_tables)
                deselect_all_button.clicked.connect(self.deselect_all_tables)
                confirm_button.clicked.connect(self.accept)
                cancel_button.clicked.connect(self.reject)
                
                # 创建布局
                button_layout = QHBoxLayout()
                button_layout.addWidget(refresh_button)
                button_layout.addWidget(select_all_button)
                button_layout.addWidget(deselect_all_button)
                button_layout.addStretch()
                button_layout.addWidget(confirm_button)
                button_layout.addWidget(cancel_button)
                
                # 添加表格信息说明
                info_label = QLabel("说明：选择需要初始化的数据表。初始化操作将清空所选表中的所有数据！")
                info_label.setStyleSheet("color: #8B0000; font-weight: bold;")
                
                main_layout = QVBoxLayout()
                main_layout.addWidget(info_label)
                main_layout.addWidget(self.table_widget)
                main_layout.addWidget(self.status_label)
                main_layout.addLayout(button_layout)
                
                self.setLayout(main_layout)
                
                # 加载数据库表信息
                self.load_database_tables()
                
            def load_database_tables(self):
                """动态加载数据库中的所有表信息"""
                try:
                    # 清空表格
                    self.table_widget.setRowCount(0)
                    
                    # 获取数据库连接
                    conn = DatabaseUtils.get_connection()
                    if not conn:
                        self.status_label.setText("错误：无法连接到数据库")
                        self.status_label.setStyleSheet("color: red;")
                        return
                    
                    cursor = conn.cursor()
                    
                    # 查询所有表名（排除系统表）
                    cursor.execute("SELECT name, sql, tbl_name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
                    tables_data = cursor.fetchall()
                    
                    # 为每个表添加到表格
                    excluded_tables = ['system_params', 'reminder_settings']
                    displayed_tables_count = 0
                    total_records_count = 0
                    
                    for table_info in tables_data:
                        table_name = table_info[0]
                        
                        # 跳过系统关键表，不显示在列表中
                        if table_name in excluded_tables:
                            continue
                        
                        # 获取表的记录数
                        try:
                            cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
                            row_count = cursor.fetchone()[0]
                            # 累加总记录数
                            total_records_count += row_count
                        except:
                            row_count = "未知"
                        
                        # 获取创建时间（从SQL语句中提取）
                        create_time = "未知"
                        
                        # 获取中文表名
                        chinese_name = self.table_name_mapping.get(table_name, table_name)
                        
                        # 添加行
                        row_position = self.table_widget.rowCount()
                        self.table_widget.insertRow(row_position)
                        displayed_tables_count += 1
                        
                        # 选择复选框
                        check_box = QCheckBox()
                        # 用户表默认不选中，避免误操作
                        if table_name == 'users':
                            check_box.setChecked(False)
                            check_box.setToolTip("用户表，默认不选中以防止误操作")
                        else:
                            check_box.setChecked(True)
                        
                        # 创建一个居中的容器
                        check_layout = QHBoxLayout()
                        check_layout.addStretch()
                        check_layout.addWidget(check_box)
                        check_layout.addStretch()
                        check_container = QWidget()
                        check_container.setLayout(check_layout)
                        self.table_widget.setCellWidget(row_position, 0, check_container)
                        
                        # 填充表格数据
                        self._add_table_item(row_position, 1, chinese_name, table_name)
                        self._add_table_item(row_position, 2, table_name)
                        self._add_table_item(row_position, 3, str(row_count))
                        self._add_table_item(row_position, 4, create_time)
                        
                    # 连接表格双击事件，用于显示users表的详细内容
                    self.table_widget.cellDoubleClicked.connect(self.on_table_double_clicked)
                    
                    # 更新状态栏，显示加载的表数量和总记录数
                    self.status_label.setText(f"成功加载 {displayed_tables_count} 个数据表，总记录数：{total_records_count}")
                    self.status_label.setStyleSheet("color: green;")
                    
                except Exception as e:
                    self.status_label.setText(f"加载表信息失败: {str(e)}")
                    self.status_label.setStyleSheet("color: red;")
                finally:
                    # 关闭连接
                    if 'conn' in locals():
                        conn.close()
            
            def _add_table_item(self, row, col, text, user_data=None):
                """添加表格项的辅助方法"""
                item = QTableWidgetItem(text)
                item.setTextAlignment(Qt.AlignCenter)
                item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                if user_data:
                    item.setData(Qt.UserRole, user_data)
                self.table_widget.setItem(row, col, item)
                
            def on_table_double_clicked(self, row, col):
                """处理表格双击事件，显示users表的详细内容"""
                # 获取表名
                table_name_item = self.table_widget.item(row, 2)
                if table_name_item and table_name_item.text() == 'users':
                    self.show_users_table_details()
                    
            def show_users_table_details(self):
                """显示users表的详细内容"""
                try:
                    # 创建用户表详情对话框
                    class UsersTableDetailsDialog(QDialog):
                        def __init__(self, parent=None):
                            super().__init__(parent)
                            self.setWindowTitle('用户表详情')
                            self.setMinimumSize(800, 600)
                            
                            # 设置当前页面
                            self.current_page = 1
                            self.records_per_page = 10
                            self.total_pages = 1
                            self.sort_column = 0
                            self.sort_order = Qt.AscendingOrder
                            self.all_users_data = []
                            
                            # 创建表格视图
                            self.users_table = QTableWidget(0, 4)
                            self.users_table.setHorizontalHeaderLabels(['用户ID', '用户名', '密码', '角色'])
                            
                            # 设置列宽
                            self.users_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
                            self.users_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
                            self.users_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
                            self.users_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeToContents)
                            
                            # 连接表头点击事件用于排序
                            self.users_table.horizontalHeader().sectionClicked.connect(self.on_header_clicked)
                            
                            # 创建分页控件
                            self.prev_button = QPushButton('上一页')
                            self.next_button = QPushButton('下一页')
                            self.page_label = QLabel('第 1 页，共 1 页')
                            
                            # 连接分页按钮信号
                            self.prev_button.clicked.connect(self.prev_page)
                            self.next_button.clicked.connect(self.next_page)
                            
                            # 创建排序说明标签
                            sort_info_label = QLabel("双击列标题可排序，密码字段已加密显示")
                            sort_info_label.setStyleSheet("color: #666;")
                            
                            # 创建布局
                            pagination_layout = QHBoxLayout()
                            pagination_layout.addWidget(self.prev_button)
                            pagination_layout.addWidget(self.page_label)
                            pagination_layout.addWidget(self.next_button)
                            pagination_layout.addStretch()
                            
                            main_layout = QVBoxLayout()
                            main_layout.addWidget(sort_info_label)
                            main_layout.addWidget(self.users_table)
                            main_layout.addLayout(pagination_layout)
                            
                            self.setLayout(main_layout)
                            
                            # 加载用户数据
                            self.load_users_data()
                            
                        def load_users_data(self):
                            """加载用户数据"""
                            try:
                                conn = DatabaseUtils.get_connection()
                                if not conn:
                                    QMessageBox.warning(self, '警告', '无法连接到数据库')
                                    return
                                
                                cursor = conn.cursor()
                                cursor.execute("SELECT id, username, password, role FROM users ORDER BY id")
                                self.all_users_data = cursor.fetchall()
                                
                                # 计算总页数
                                self.total_pages = (len(self.all_users_data) + self.records_per_page - 1) // self.records_per_page
                                
                                # 显示第一页数据
                                self.display_current_page()
                                
                                # 更新分页信息
                                self.update_pagination_info()
                                
                            except Exception as e:
                                QMessageBox.critical(self, '错误', f'加载用户数据失败: {str(e)}')
                            finally:
                                if 'conn' in locals():
                                    conn.close()
                            
                        def display_current_page(self):
                            """显示当前页的数据"""
                            # 清空表格
                            self.users_table.setRowCount(0)
                            
                            # 计算当前页的数据范围
                            start_index = (self.current_page - 1) * self.records_per_page
                            end_index = min(start_index + self.records_per_page, len(self.all_users_data))
                            
                            # 获取当前页的数据（已排序）
                            page_data = self.sort_data(self.all_users_data[start_index:end_index])
                            
                            # 填充表格
                            for row_data in page_data:
                                row_position = self.users_table.rowCount()
                                self.users_table.insertRow(row_position)
                                
                                # 用户ID
                                id_item = QTableWidgetItem(str(row_data[0]))
                                id_item.setTextAlignment(Qt.AlignCenter)
                                id_item.setFlags(id_item.flags() & ~Qt.ItemIsEditable)
                                self.users_table.setItem(row_position, 0, id_item)
                                
                                # 用户名
                                username_item = QTableWidgetItem(str(row_data[1]))
                                username_item.setTextAlignment(Qt.AlignCenter)
                                username_item.setFlags(username_item.flags() & ~Qt.ItemIsEditable)
                                self.users_table.setItem(row_position, 1, username_item)
                                
                                # 密码（加密显示）
                                password_item = QTableWidgetItem('●●●●●●●●')
                                password_item.setTextAlignment(Qt.AlignCenter)
                                password_item.setFlags(password_item.flags() & ~Qt.ItemIsEditable)
                                password_item.setToolTip("密码已加密存储")
                                self.users_table.setItem(row_position, 2, password_item)
                                
                                # 角色
                                role_item = QTableWidgetItem(str(row_data[3]))
                                role_item.setTextAlignment(Qt.AlignCenter)
                                role_item.setFlags(role_item.flags() & ~Qt.ItemIsEditable)
                                self.users_table.setItem(row_position, 3, role_item)
                                
                        def sort_data(self, data):
                            """根据当前排序规则对数据进行排序"""
                            # 如果数据为空，直接返回
                            if not data:
                                return data
                            
                            # 根据排序列和顺序对数据进行排序
                            sorted_data = sorted(data, key=lambda x: x[self.sort_column], reverse=(self.sort_order == Qt.DescendingOrder))
                            return sorted_data
                            
                        def on_header_clicked(self, column):
                            """处理表头点击事件"""
                            # 更新排序信息
                            if column == self.sort_column:
                                # 切换排序顺序
                                self.sort_order = Qt.DescendingOrder if self.sort_order == Qt.AscendingOrder else Qt.AscendingOrder
                            else:
                                # 重置排序顺序为升序
                                self.sort_column = column
                                self.sort_order = Qt.AscendingOrder
                            
                            # 重新显示当前页数据
                            self.display_current_page()
                            
                        def prev_page(self):
                            """上一页"""
                            if self.current_page > 1:
                                self.current_page -= 1
                                self.display_current_page()
                                self.update_pagination_info()
                                
                        def next_page(self):
                            """下一页"""
                            if self.current_page < self.total_pages:
                                self.current_page += 1
                                self.display_current_page()
                                self.update_pagination_info()
                                
                        def update_pagination_info(self):
                            """更新分页信息"""
                            self.page_label.setText(f'第 {self.current_page} 页，共 {self.total_pages} 页')
                            self.prev_button.setEnabled(self.current_page > 1)
                            self.next_button.setEnabled(self.current_page < self.total_pages)
                    
                    # 显示对话框
                    dialog = UsersTableDetailsDialog(self)
                    dialog.exec_()
                    
                except Exception as e:
                    QMessageBox.critical(self, '错误', f'显示用户表详情失败: {str(e)}')
            
            def select_all_tables(self):
                """全选所有表"""
                for row in range(self.table_widget.rowCount()):
                    container_widget = self.table_widget.cellWidget(row, 0)
                    if container_widget:
                        layout = container_widget.layout()
                        for i in range(layout.count()):
                            item = layout.itemAt(i)
                            if isinstance(item.widget(), QCheckBox):
                                item.widget().setChecked(True)
            
            def deselect_all_tables(self):
                """取消全选所有表"""
                for row in range(self.table_widget.rowCount()):
                    container_widget = self.table_widget.cellWidget(row, 0)
                    if container_widget:
                        layout = container_widget.layout()
                        for i in range(layout.count()):
                            item = layout.itemAt(i)
                            if isinstance(item.widget(), QCheckBox):
                                item.widget().setChecked(False)
            
            def get_selected_tables(self):
                """获取用户选择的数据表"""
                selected_tables = []
                for row in range(self.table_widget.rowCount()):
                    # 获取包含复选框的容器widget
                    container_widget = self.table_widget.cellWidget(row, 0)
                    if not container_widget:
                        continue
                        
                    # 从容器的布局中获取复选框
                    layout = container_widget.layout()
                    check_box = None
                    for i in range(layout.count()):
                        item = layout.itemAt(i)
                        if isinstance(item.widget(), QCheckBox):
                            check_box = item.widget()
                            break
                    
                    if check_box and check_box.isChecked():
                        # 尝试从不同列获取表名
                        table_name = None
                        # 从中文列获取用户数据
                        if self.table_widget.item(row, 1):
                            table_name = self.table_widget.item(row, 1).data(Qt.UserRole)
                        # 如果没找到，使用英文列的文本
                        if not table_name and self.table_widget.item(row, 2):
                            table_name = self.table_widget.item(row, 2).text()
                        
                        if table_name:
                            selected_tables.append(table_name)
                return selected_tables
        
        # 显示对话框
        dialog = DataInitDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            # 获取用户选择的数据表
            selected_tables = dialog.get_selected_tables()
            
            if not selected_tables:
                QMessageBox.warning(self, '警告', '请至少选择一个数据表进行初始化!')
                return
            
            # 再次确认操作 - 从表格中获取选中表的中文名称
            selected_table_names = []
            for row in range(dialog.table_widget.rowCount()):
                # 获取包含复选框的容器widget
                container_widget = dialog.table_widget.cellWidget(row, 0)
                if not container_widget:
                    continue
                    
                # 从容器的布局中获取复选框
                layout = container_widget.layout()
                check_box = None
                for i in range(layout.count()):
                    item = layout.itemAt(i)
                    if isinstance(item.widget(), QCheckBox):
                        check_box = item.widget()
                        break
                
                if check_box and check_box.isChecked():
                    # 获取中文表名
                    if dialog.table_widget.item(row, 1):
                        chinese_name = dialog.table_widget.item(row, 1).text()
                        selected_table_names.append(chinese_name)
            
            tables_text = '、'.join(selected_table_names)
            reply = QMessageBox.question(self, '最终确认', 
                                        f'您确定要初始化以下数据表吗?\n{tables_text}\n\n' \
                                        '此操作将清空所选表中的所有数据!',
                                        QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                # 显示进度对话框
                progress_dialog = QProgressDialog('正在初始化数据...', None, 0, 100, self)
                progress_dialog.setWindowTitle('数据初始化')
                progress_dialog.setWindowModality(Qt.WindowModal)
                progress_dialog.setValue(0)
                
                # 创建日志窗口
                log_window = QTextEdit()
                log_window.setReadOnly(True)
                log_window.setWindowTitle('数据初始化日志')
                log_window.resize(800, 400)
                log_window.show()
                
                try:
                    # 使用线程执行初始化
                    from db_utils import DatabaseUtils
                    
                    class InitThread(QThread):
                        update_log = pyqtSignal(str)
                        update_progress = pyqtSignal(int)
                        finished = pyqtSignal(bool, list)
                        
                        def __init__(self, selected_tables):
                            super().__init__()
                            self.selected_tables = selected_tables
                        
                        def run(self):
                            results = []
                            success = True
                            
                            try:
                                # 连接数据库 - 添加重试逻辑
                                max_retries = 3
                                retry_count = 0
                                conn = None
                                
                                while retry_count < max_retries and conn is None:
                                    if retry_count > 0:
                                        results.append(f'尝试重新连接数据库 ({retry_count}/{max_retries-1})...')
                                        import time
                                        time.sleep(1)  # 等待1秒后重试
                                    
                                    conn = DatabaseUtils.get_connection()
                                    retry_count += 1
                                
                                if conn is None:
                                    results.append('❌ 数据库连接失败，已达到最大重试次数')
                                    success = False
                                    self.finished.emit(success, results)
                                    return
                                
                                cursor = conn.cursor()
                                db_path = DatabaseUtils.get_db_path()
                                
                                results.append(f'连接数据库: {db_path}')
                                self.update_progress.emit(20)
                                
                                # 清空所选数据表
                                for i, table_name in enumerate(self.selected_tables):
                                    try:
                                        cursor.execute(f'DELETE FROM {table_name}')
                                        results.append(f'✅ 已清空表: {table_name}')
                                    except Exception as e:
                                        results.append(f'❌ 清空表失败 {table_name}: {str(e)}')
                                        success = False
                                    
                                    # 更新进度
                                    self.update_progress.emit(20 + int(60 * (i+1)/len(self.selected_tables)))
                                
                                # 插入默认数据
                                try:
                                    # 提醒设置表
                                    if 'reminder_settings' in self.selected_tables:
                                        cursor.execute("SELECT COUNT(*) FROM reminder_settings")
                                        if cursor.fetchone()[0] == 0:
                                            cursor.execute("INSERT INTO reminder_settings (contract_reminder_days, rent_reminder_days) VALUES (?, ?)", (30, 7))
                                            results.append('✅ 已插入默认提醒设置')
                                    
                                    # 用户表
                                    if 'users' in self.selected_tables:
                                        cursor.execute("SELECT COUNT(*) FROM users WHERE username = ?", ('admin',))
                                        if cursor.fetchone()[0] == 0:
                                            cursor.execute("INSERT INTO users (username, password, role) VALUES (?, ?, ?)", ('admin', 'admin', '管理员'))
                                            results.append('✅ 已插入默认管理员用户')
                                    
                                    # 提交更改
                                    conn.commit()
                                    self.update_progress.emit(90)
                                except Exception as e:
                                    results.append(f'❌ 插入默认数据失败: {str(e)}')
                                    success = False
                                    conn.rollback()
                                
                                conn.close()
                                
                            except Exception as e:
                                results.append(f'❌ 初始化过程发生错误: {str(e)}')
                                success = False
                            
                            self.update_progress.emit(100)
                            self.finished.emit(success, results)
                    
                    init_thread = InitThread(selected_tables)
                    
                    # 连接信号
                    def update_log_slot(message):
                        log_window.append(message)
                        log_window.verticalScrollBar().setValue(log_window.verticalScrollBar().maximum())
                    
                    init_thread.update_log.connect(update_log_slot)
                    init_thread.update_progress.connect(progress_dialog.setValue)
                    
                    # 处理完成信号
                    def on_finished(success, results):
                        # 显示所有结果
                        for result in results:
                            log_window.append(result)
                        
                        progress_dialog.setValue(100)
                        
                        if success:
                            QMessageBox.information(self, '成功', '数据初始化成功,系统将自动重启')
                            # 关闭所有窗口
                            for window in QApplication.topLevelWidgets():
                                window.close()
                            # 延迟重启,给消息框时间显示
                            QTimer.singleShot(1000, self.restart_application)
                        else:
                            QMessageBox.critical(self, '失败', 
                                               '数据初始化遇到问题。\n' 
                                               '请查看日志窗口获取详细信息。')
                    
                    init_thread.finished.connect(on_finished)
                    
                    # 开始线程
                    init_thread.start()
                    
                    # 等待进度对话框关闭
                    progress_dialog.exec_()
                    
                except Exception as e:
                    QMessageBox.critical(self, '错误', f'数据初始化失败: {str(e)}')
                
    def restart_application(self):
        """重启应用程序"""
        python = sys.executable
        os.execl(python, python, *sys.argv)
        
    def optimizeDatabase(self):
        """数据库优化功能 - 执行数据库性能优化操作"""
        from logger_module import log_info, log_warning, log_error
        from PyQt5.QtWidgets import QMessageBox, QProgressDialog
        from PyQt5.QtCore import Qt, QTimer, QProcess
        from PyQt5.QtWidgets import QApplication
        import sys
        import os
        from database_optimization import DatabaseOptimizer, OptimizerConfig
        
        log_info("开始数据库优化操作")
        
        # 权限验证 - 确保用户具有系统设置权限
        if not self.is_authenticated:
            log_warning("用户权限不足，无法执行数据库优化")
            QMessageBox.warning(self, '权限不足', '您没有执行数据库优化的权限')
            return
        
        # 确认操作
        reply = QMessageBox.question(self, '确认', '数据库优化将执行索引重建、碎片整理和冗余数据清理等操作。\n\n操作完成后系统将自动重启以应用优化效果。是否继续？',
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            log_info("用户取消了数据库优化操作")
            return
        
        # 显示加载状态
        progress_dialog = QProgressDialog('正在执行数据库优化...', None, 0, 100, self)
        progress_dialog.setWindowTitle('数据库优化')
        progress_dialog.setWindowModality(Qt.WindowModal)
        progress_dialog.setMinimumDuration(0)
        progress_dialog.setValue(0)
        progress_dialog.show()
        
        # 进度回调函数
        def update_progress(progress, message):
            """更新进度对话框"""
            if progress >= 0:
                progress_dialog.setValue(progress)
                progress_dialog.setLabelText(message)
                QApplication.processEvents()  # 处理UI事件
            else:
                # 错误状态
                progress_dialog.setLabelText(f"错误: {message}")
        
        # 执行优化操作
        try:
            # 禁用所有与数据库相关的操作，防止数据不一致
            self.create_db_btn.setEnabled(False)
            self.select_db_btn.setEnabled(False)
            self.backup_btn.setEnabled(False)
            self.restore_btn.setEnabled(False)
            self.init_btn.setEnabled(False)
            self.optimize_db_btn.setEnabled(False)
            self.view_log_btn.setEnabled(False)
            
            update_progress(10, "正在初始化优化器...")
            
            # 获取数据库连接
            from db_utils import DatabaseUtils
            conn = DatabaseUtils.get_connection()
            
            # 创建优化器配置
            config = OptimizerConfig()
            
            # 创建优化器实例
            optimizer = DatabaseOptimizer(config)
            
            log_info("开始执行数据库优化操作")
            
            # 执行优化，传入连接和进度回调
            result = optimizer.optimize(connection=conn, progress_callback=update_progress)
            
            # 提交更改
            conn.commit()
            
            log_info(f"数据库优化操作完成，结果: {result.success}")
            
            # 关闭连接
            conn.close()
            
            if result.success:
                # 显示成功消息
                QMessageBox.information(self, '成功', '数据库优化成功，系统将自动重启以应用优化效果')
                
                # 记录操作成功日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="系统设置",
                    operation_content="数据库优化",
                    operation_result="成功",
                    detail={
                        "操作": "完成数据库优化",
                        "优化表数": result.tables_optimized,
                        "执行时间": f"{result.get_duration():.2f}秒"
                    }
                )
                
                # 延迟重启应用
                QTimer.singleShot(1000, self.restart_application)
            else:
                # 显示失败消息
                error_msg = f"数据库优化部分操作失败\n\n完成步骤: {len(result.steps_completed)}\n失败步骤: {len(result.steps_failed)}"
                if result.errors:
                    error_msg += f"\n\n错误信息:\n{chr(10).join(result.errors[:3])}"
                
                QMessageBox.warning(self, '优化完成但有警告', error_msg)
                
                # 记录操作结果日志
                self.record_operation(
                    user_id=self.auth_manager.current_user_id,
                    username=self.auth_manager.current_user,
                    operation_module="系统设置",
                    operation_content="数据库优化",
                    operation_result="部分成功",
                    detail={
                        "完成步骤": result.steps_completed,
                        "失败步骤": result.steps_failed,
                        "错误信息": result.errors[:3]  # 只记录前3个错误
                    }
                )
            
        except Exception as e:
            log_error(f"数据库优化失败: {str(e)}")
            QMessageBox.critical(self, '错误', f'数据库优化失败: {str(e)}')
            # 记录操作失败日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="数据库优化",
                operation_result="失败",
                detail={"错误信息": str(e)}
            )
        finally:
            # 重新启用数据库操作
            try:
                self.create_db_btn.setEnabled(True)
                self.select_db_btn.setEnabled(True)
                self.backup_btn.setEnabled(True)
                self.restore_btn.setEnabled(True)
                self.init_btn.setEnabled(True)
                self.optimize_db_btn.setEnabled(True)
                self.view_log_btn.setEnabled(True)
            except:
                pass  # 如果按钮不可用，忽略错误
    
    def show_authentication_prompt(self):
        """显示系统设置访问的密码验证对话框"""
        from PyQt5.QtCore import QTimer
        from user_auth import SystemSettingPasswordDialog
        from PyQt5.QtWidgets import QApplication
        
        dialog = SystemSettingPasswordDialog(self.auth_manager.current_user)
        if dialog.exec_() == QDialog.Accepted:
            # 密码验证成功
            self.is_authenticated = True
            self.auth_prompt.hide()
            self.main_frame.show()
            # 加载用户数据、软件信息、提醒设置、配置文件信息和自动备份设置
            self.loadUserData()
            self.loadSoftwareInfo()
            self.loadReminderSettings()
            self.loadConfigInfo()
            self.loadAutoBackupSettings()
            
            # 确保主窗口大小合适（调用MainWindow中的自适应调整方法）
            main_window = None
            for widget in QApplication.topLevelWidgets():
                if hasattr(widget, '__class__') and widget.__class__.__name__ == 'MainWindow':
                    main_window = widget
                    # 触发窗口大小自适应调整
                    if hasattr(main_window, '_ensure_proper_window_size'):
                        main_window._ensure_proper_window_size()
                    break
            
            # 记录操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="访问系统设置",
                operation_result="成功",
                detail={"验证结果": "密码验证成功"}
            )
            return True
        else:
            # 密码验证失败
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="访问系统设置",
                operation_result="失败",
                detail={"验证结果": "密码验证失败"}
            )
            return False
    
    def loadReminderSettings(self):
        """从数据库加载提醒设置和屏幕超时设置"""
        from db_utils import DatabaseUtils
        try:
            # 连接数据库
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 查询提醒设置和屏幕超时设置
            cursor.execute("SELECT contract_reminder_days, rent_reminder_days, screen_timeout_minutes FROM reminder_settings LIMIT 1")
            result = cursor.fetchone()
            
            # 设置输入框值
            if result:
                self.contract_reminder_input.setText(str(result[0]))
                self.rent_reminder_input.setText(str(result[1]))
                # 检查是否有屏幕超时设置值
                if len(result) > 2 and result[2] is not None:
                    self.timeout_input.setText(str(result[2]))
                else:
                    self.timeout_input.setText("30")  # 默认30分钟
            else:
                # 设置默认值
                self.contract_reminder_input.setText("30")
                self.rent_reminder_input.setText("7")
                self.timeout_input.setText("30")  # 屏幕超时默认30分钟
                
        except Exception as e:
            QMessageBox.warning(self, '警告', f'加载提醒设置失败: {str(e)}')
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def loadConfigInfo(self):
        """加载并显示当前配置文件路径信息"""
        try:
            from config_utils import config_manager
            # 获取当前配置文件路径
            current_path = config_manager.get_config_path()
            # 显示配置文件路径
            self.current_config_path.setText(current_path)
            log_info(f"已加载配置文件路径信息: {current_path}")
        except Exception as e:
            log_error(f"加载配置文件路径信息时出错: {str(e)}")
            self.current_config_path.setText(f"加载失败: {str(e)}")
    
    def selectBackupPath(self):
        """选择自动备份文件保存路径"""
        try:
            from PyQt5.QtWidgets import QFileDialog
            # 打开目录选择对话框
            path = QFileDialog.getExistingDirectory(
                self, '选择备份文件夹', 
                os.path.expanduser('~'),
                QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks
            )
            if path:
                self.backup_path_input.setText(path)
        except Exception as e:
            QMessageBox.warning(self, '警告', f'选择备份路径失败: {str(e)}')
    
    def loadAutoBackupSettings(self):
        """从数据库加载自动备份设置"""
        try:
            # 初始化备份管理器（如果尚未初始化）
            if not hasattr(self, '_backup_manager'):
                self._backup_manager = AutoBackupManager()
            
            # 加载备份设置
            settings = self._backup_manager.load_settings()
            
            # 设置UI组件值（使用字典访问方式）
            self.auto_backup_enable.setChecked(settings.get('enabled', False))
            
            # 备份频率
            frequency = settings.get('frequency', '每天')
            if frequency in ['每天', '每周', '每月']:
                self.frequency_combo.setCurrentText(frequency)
            else:
                self.frequency_combo.setCurrentText('每天')
            
            # 备份时间
            backup_time = settings.get('backup_time', '00:00')
            if backup_time:
                from PyQt5.QtCore import QTime
                time_parts = backup_time.split(':')
                if len(time_parts) == 2:
                    try:
                        hour, minute = int(time_parts[0]), int(time_parts[1])
                        self.backup_time_edit.setTime(QTime(hour, minute))
                    except:
                        pass
            else:
                from PyQt5.QtCore import QTime
                self.backup_time_edit.setTime(QTime(0, 0))
            
            # 备份路径
            backup_path = settings.get('backup_path', '')
            if backup_path:
                self.backup_path_input.setText(backup_path)
            else:
                self.backup_path_input.setText('')
            
            # 更新状态显示
            self.updateBackupStatusDisplay()
            
        except Exception as e:
            QMessageBox.warning(self, '警告', f'加载自动备份设置失败: {str(e)}')
    
    def saveAutoBackupSettings(self):
        """保存自动备份设置到数据库"""
        try:
            # 初始化备份管理器（如果尚未初始化）
            if not hasattr(self, '_backup_manager'):
                self._backup_manager = AutoBackupManager()
            
            # 获取设置值
            enabled = self.auto_backup_enable.isChecked()
            frequency = self.frequency_combo.currentText()
            backup_time = self.backup_time_edit.time().toString('HH:mm')
            backup_path = self.backup_path_input.text()
            
            # 创建备份设置对象
            settings = BackupSettings(
                enabled=enabled,
                frequency=frequency,
                backup_time=backup_time,
                backup_path=backup_path
            )
            
            # 验证和保存设置
            if not self._backup_manager.save_settings(settings):
                # 如果保存失败，管理器会记录错误
                QMessageBox.warning(self, '警告', '保存自动备份设置失败，请检查设置是否有效!')
                return
            
            # 更新状态显示
            self.updateBackupStatusDisplay()
            
            # 立即应用新的备份策略
            self.applyBackupStrategy()
            
            QMessageBox.information(self, '成功', '自动备份设置已保存!')
            
            # 记录操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="修改自动备份设置",
                operation_result="成功",
                detail={
                    "启用状态": "已启用" if enabled else "已禁用",
                    "备份频率": frequency,
                    "备份时间": backup_time,
                    "备份路径": backup_path
                }
            )
            
        except Exception as e:
            QMessageBox.critical(self, '错误', f'保存自动备份设置失败: {str(e)}')
    
    def updateBackupStatusDisplay(self):
        """更新自动备份状态显示"""
        if self.auto_backup_enable.isChecked():
            frequency = self.frequency_combo.currentText()
            backup_time = self.backup_time_edit.time().toString('HH:mm')
            status_text = f'自动备份状态: 已启用 ({frequency} {backup_time})'
            self.backup_status_label.setStyleSheet('color: #28a745; font-size: 12px; margin-top: 10px;')
        else:
            status_text = '自动备份状态: 未启用'
            self.backup_status_label.setStyleSheet('color: #666; font-size: 12px; margin-top: 10px;')
        self.backup_status_label.setText(status_text)
    
    def applyBackupStrategy(self):
        """应用新的备份策略，启动或停止定时备份任务"""
        try:
            # 初始化备份管理器（如果尚未初始化）
            if not hasattr(self, '_backup_manager'):
                self._backup_manager = AutoBackupManager()
            
            # 清理旧的定时器（如果存在）
            if hasattr(self, '_backup_timer'):
                self._backup_timer.stop()
                delattr(self, '_backup_timer')
            
            # 启动或停止自动备份服务
            if self.auto_backup_enable.isChecked():
                # 加载当前设置
                settings = self._backup_manager.load_settings()
                # 启动备份服务 - 使用auto_backup模块的完整功能
                self._backup_manager.start_backup_service(settings)
                log_info("自动备份服务已通过AutoBackupManager启动")
            else:
                # 停止备份服务
                self._backup_manager.stop_backup_service()
                log_info("自动备份服务已停止")
                
        except Exception as e:
            log_error(f'应用备份策略失败: {str(e)}')
            QMessageBox.warning(self, '警告', f'应用备份策略失败: {str(e)}')
    
    def setCustomConfigPath(self):
        """设置自定义配置文件路径"""
        try:
            from PyQt5.QtWidgets import QFileDialog
            # 打开文件选择对话框
            file_path, _ = QFileDialog.getSaveFileName(
                self, 
                '选择配置文件',
                '',
                '配置文件 (*.json);;所有文件 (*)'
            )
            
            if file_path:
                # 调用主窗口的设置配置文件路径方法
                main_window = self.parent().parent() if self.parent() else None
                if main_window and hasattr(main_window, 'set_custom_config_path'):
                    success = main_window.set_custom_config_path(file_path)
                    if success:
                        # 更新显示
                        self.loadConfigInfo()
                        # 记录操作日志
                        self.record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="系统设置",
                            operation_content="设置自定义配置文件路径",
                            operation_result="成功",
                            detail=f"新路径: {file_path}"
                        )
                else:
                    # 直接使用config_manager设置
                    from config_utils import config_manager
                    success = config_manager.set_config_path(file_path)
                    if success:
                        # 更新显示
                        self.loadConfigInfo()
                        QMessageBox.information(self, "配置成功", 
                                            f"配置文件路径已更改为:\n{file_path}\n\n系统配置已重新加载。")
                        # 记录操作日志
                        self.record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="系统设置",
                            operation_content="设置自定义配置文件路径",
                            operation_result="成功",
                            detail=f"新路径: {file_path}"
                        )
        except Exception as e:
            log_error(f"设置自定义配置文件路径时出错: {str(e)}")
            QMessageBox.critical(self, '错误', f'设置配置文件路径失败: {str(e)}')
            # 记录操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="设置自定义配置文件路径",
                operation_result="失败",
                detail=str(e)
            )
    
    def resetConfigPath(self):
        """重置配置文件路径为默认值"""
        try:
            from PyQt5.QtWidgets import QMessageBox
            # 确认对话框
            reply = QMessageBox.question(
                self, 
                '确认重置', 
                '确定要将配置文件路径重置为默认值吗？\n这将使用程序目录下的config.json文件。',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                # 调用主窗口的设置配置文件路径方法（传入None表示重置）
                main_window = self.parent().parent() if self.parent() else None
                if main_window and hasattr(main_window, 'set_custom_config_path'):
                    success = main_window.set_custom_config_path(None)
                    if success:
                        # 更新显示
                        self.loadConfigInfo()
                        # 记录操作日志
                        self.record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="系统设置",
                            operation_content="重置配置文件路径",
                            operation_result="成功",
                            detail="已重置为默认路径"
                        )
                else:
                    # 直接使用config_manager重置
                    from config_utils import config_manager
                    success = config_manager.set_config_path(None)
                    if success:
                        # 更新显示
                        self.loadConfigInfo()
                        QMessageBox.information(self, "配置成功", 
                                            "配置文件路径已重置为默认值。")
                        # 记录操作日志
                        self.record_operation(
                            user_id=self.auth_manager.current_user_id,
                            username=self.auth_manager.current_user,
                            operation_module="系统设置",
                            operation_content="重置配置文件路径",
                            operation_result="成功",
                            detail="已重置为默认路径"
                        )
        except Exception as e:
            log_error(f"重置配置文件路径时出错: {str(e)}")
            QMessageBox.critical(self, '错误', f'重置配置文件路径失败: {str(e)}')
            # 记录操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="重置配置文件路径",
                operation_result="失败",
                detail=str(e)
            )
            
    def saveReminderSettings(self):
        """保存提醒设置和屏幕超时设置到数据库"""
        from db_utils import DatabaseUtils
        try:
            # 获取输入框值
            contract_days = self.contract_reminder_input.text()
            rent_days = self.rent_reminder_input.text()
            timeout_minutes = self.timeout_input.text()
            
            # 验证输入
            if not contract_days or not rent_days or not timeout_minutes:
                QMessageBox.warning(self, '警告', '请填写所有设置项!')
                return
            
            # 连接数据库
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 检查是否存在reminder_settings表
            cursor.execute("""SELECT count(*) FROM sqlite_master WHERE type='table' AND name='reminder_settings'""")
            if cursor.fetchone()[0] == 0:
                # 创建表
                cursor.execute("""CREATE TABLE reminder_settings (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    contract_reminder_days INTEGER,
                    rent_reminder_days INTEGER,
                    screen_timeout_minutes INTEGER DEFAULT 30
                )""")
            else:
                # 检查是否有screen_timeout_minutes字段,没有则添加
                cursor.execute("""PRAGMA table_info(reminder_settings)""")
                columns = [column[1] for column in cursor.fetchall()]
                if 'screen_timeout_minutes' not in columns:
                    cursor.execute("ALTER TABLE reminder_settings ADD COLUMN screen_timeout_minutes INTEGER DEFAULT 30")
            
            # 检查是否已有记录
            cursor.execute("SELECT id FROM reminder_settings LIMIT 1")
            result = cursor.fetchone()
            
            if result:
                # 更新现有记录
                cursor.execute(
                    "UPDATE reminder_settings SET contract_reminder_days=?, rent_reminder_days=?, screen_timeout_minutes=? WHERE id=?",
                    (int(contract_days), int(rent_days), int(timeout_minutes), result[0])
                )
            else:
                # 插入新记录
                cursor.execute(
                    "INSERT INTO reminder_settings (contract_reminder_days, rent_reminder_days, screen_timeout_minutes) VALUES (?, ?, ?)",
                    (int(contract_days), int(rent_days), int(timeout_minutes))
                )
            
            conn.commit()
            
            # 记录操作日志
            # 通知MainWindow更新屏幕超时时间
            from PyQt5.QtWidgets import QApplication
            for widget in QApplication.topLevelWidgets():
                if hasattr(widget, 'updateScreenTimeout'):
                    widget.updateScreenTimeout(timeout_minutes)
                    break
            
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="更新提醒设置和屏幕超时设置",
                operation_result="成功",
                detail={"合同提前提醒天数": contract_days, "租金提前提醒天数": rent_days, "屏幕超时时间": f"{timeout_minutes}分钟"}
            )
            
            QMessageBox.information(self, '成功', '提醒设置和屏幕超时设置保存成功!')
            
        except Exception as e:
            QMessageBox.critical(self, '错误', f'保存提醒设置失败: {str(e)}')
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def loadSoftwareInfo(self):
        """从数据库加载软件信息"""
        from db_utils import DatabaseUtils
        try:
            # 连接数据库
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 检查是否存在system_params表
            cursor.execute("""SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'""")
            if cursor.fetchone()[0] == 0:
                # 创建表
                cursor.execute("""CREATE TABLE system_params (
                    key TEXT PRIMARY KEY,
                    value TEXT
                )""")
                conn.commit()
            
            # 查询软件信息
            params = {}
            for key in ['software_brand', 'software_name', 'software_version', 'development_time']:
                cursor.execute("SELECT value FROM system_params WHERE key=?", (key,))
                result = cursor.fetchone()
                params[key] = result[0] if result else ''
            
            # 设置输入框值
            self.brand_input.setText(params['software_brand'])
            self.name_input.setText(params['software_name'])
            self.version_input.setText(params['software_version'])
            self.dev_time_input.setText(params['development_time'])
            
        except Exception as e:
            QMessageBox.warning(self, '警告', f'加载软件信息失败: {str(e)}')
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def saveSoftwareInfo(self):
        """保存软件信息到数据库"""
        from db_utils import DatabaseUtils
        try:
            # 获取输入框值
            brand = self.brand_input.text()
            name = self.name_input.text()
            version = self.version_input.text()
            dev_time = self.dev_time_input.text()
            
            # 连接数据库
            conn = DatabaseUtils.get_connection()
            if conn is None:
                QMessageBox.warning(self, '警告', '无法连接到数据库!')
                return
            cursor = conn.cursor()
            
            # 保存参数
            params = {
                'software_brand': brand,
                'software_name': name,
                'software_version': version,
                'development_time': dev_time
            }
            
            for key, value in params.items():
                cursor.execute(
                    "INSERT OR REPLACE INTO system_params (key, value) VALUES (?, ?)",
                    (key, value)
                )
            
            conn.commit()
            
            # 记录操作日志
            self.record_operation(
                user_id=self.auth_manager.current_user_id,
                username=self.auth_manager.current_user,
                operation_module="系统设置",
                operation_content="更新软件信息",
                operation_result="成功",
                detail={"品牌": brand, "名称": name, "版本": version, "开发时间": dev_time}
            )
            
            QMessageBox.information(self, '成功', '软件信息保存成功!')
            
        except Exception as e:
            QMessageBox.critical(self, '错误', f'保存软件信息失败: {str(e)}')
        finally:
            if conn:
                conn.close()
    
    def show_manual_solution(self):
        """显示手动解决数据库锁定问题的方法"""
        manual_steps = (
            '数据库文件被锁定,无法自动处理。请尝试以下手动方法:\n\n'
            '1. 关闭所有可能正在使用数据库的程序\n'
            '   (包括Python、应用程序本身、任何数据库工具等)\n\n'
            '2. 手动删除或重命名以下文件:\n'
            f'   {os.path.join(os.path.dirname(os.path.abspath(__file__)), "rental_contract.db")}\n\n'
            '3. 重新启动应用程序,它将自动创建新的数据库\n\n'
            '4. 如果以上方法都不行,请运行我们提供的工具:\n'
            '   在命令提示符中执行: python db_utils.py'
        )
        
        QMessageBox.information(self, '手动解决方案', manual_steps)

# 导入用户认证模块
from user_auth import auth_manager


def get_software_info():
    """获取软件信息参数,供系统内各功能模块调用和引用
    
    Returns:
        dict: 包含软件品牌、名称、版本和开发时间的字典
    """
    software_info = {
        'brand': '',
        'name': '',
        'version': '',
        'dev_time': ''
    }
    
    try:
        # 连接数据库
        # 使用DatabaseUtils获取数据库连接
        from db_utils import DatabaseUtils
        conn = DatabaseUtils.get_connection()
        cursor = conn.cursor()
        
        # 查询软件信息参数
        cursor.execute("SELECT key, value FROM system_params WHERE key IN (?, ?, ?, ?)",
                      ('software_brand', 'software_name', 'software_version', 'development_time'))
        
        # 处理结果
        for key, value in cursor.fetchall():
            if key == 'software_brand':
                software_info['brand'] = value
            elif key == 'software_name':
                software_info['name'] = value
            elif key == 'software_version':
                software_info['version'] = value
            elif key == 'development_time':
                software_info['dev_time'] = value
    except Exception as e:
        # 发生错误时返回默认值
        pass
    finally:
        if conn:
            conn.close()
    
    return software_info

def cleanup_resources():
    """应用程序退出前的资源清理函数
    
    负责在应用程序关闭时清理所有关键资源，包括：
    - 关闭数据库连接池中的所有连接
    - 确保日志系统完成所有日志写入
    - 释放其他系统资源
    """
    try:
        # 导入DatabaseUtils以清理数据库连接池
        from db_utils import DatabaseUtils
        
        # 检查DatabaseUtils是否已初始化
        if hasattr(DatabaseUtils, '_connection_pool'):
            # 尝试安全关闭连接池中的所有连接
            log_info("开始清理数据库连接池资源")
            
            # 获取并清空连接池
            connections = []
            with DatabaseUtils._pool_lock:
                # 保存当前连接池中的所有连接
                connections = DatabaseUtils._connection_pool.copy()
                # 清空连接池
                DatabaseUtils._connection_pool = []
                # 清空活跃连接记录
                DatabaseUtils._active_connections = {}
            
            # 关闭每个连接
            for conn in connections:
                try:
                    conn.close()
                    log_debug("成功关闭连接池中的连接")
                except Exception as e:
                    # 避免在清理阶段抛出异常
                    pass
            
            log_info(f"已清理数据库连接池，关闭了 {len(connections)} 个连接")
            
        # 确保日志系统完成所有日志写入
        log_info("应用程序正在安全关闭...")
        
        # 执行垃圾回收以释放资源
        import gc
        gc.collect()
        
    except Exception as e:
        # 避免在清理阶段抛出异常
        pass

# 主函数
if __name__ == '__main__':
    # 创建应用程序实例
    app = QApplication(sys.argv)
    
    # 应用现代主题
    apply_global_theme(app)
    
    # 设置应用程序的退出处理
    app.aboutToQuit.connect(cleanup_resources)
    
    # 用户登录
    if auth_manager.login():
        # 登录成功,创建并显示主窗口
        window = MainWindow()
        window.showMaximized()
        
        # 启动应用程序
        try:
            sys.exit(app.exec_())
        finally:
            # 确保资源清理
            cleanup_resources()
    else:
        # 登录失败或取消,退出应用程序
        try:
            cleanup_resources()
        finally:
            sys.exit(0)